From fe7a8e8ca867e71a29e99ef7bd755cd548b17f64 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Mon, 26 Nov 2007 17:17:01 +0000 Subject: [PATCH] Reversed incorrect checkin git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@7438 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../messages/webscripts-test-help.txt | 100 +++ .../alfresco/messages/webscripts.properties | 86 ++ .../templates/webscripts/fbml.status.ftl | 46 + .../org/alfresco/index.get.desc.xml | 6 + .../org/alfresco/index.get.html.ftl | 36 + .../org/alfresco/index.post.desc.xml | 6 + .../org/alfresco/index.post.html.ftl | 25 + .../org/alfresco/indexall.get.desc.xml | 6 + .../org/alfresco/indexall.get.html.ftl | 54 ++ .../org/alfresco/indexall.get.mediawiki.ftl | 64 ++ .../org/alfresco/indexpackage.get.desc.xml | 5 + .../org/alfresco/indexpackage.get.html.ftl | 61 ++ .../org/alfresco/indexuri.get.desc.xml | 6 + .../org/alfresco/indexuri.get.html.ftl | 61 ++ .../alfresco/scriptdescription.get.desc.xml | 6 + .../org/alfresco/scriptdump.get.desc.xml | 7 + .../org/alfresco/scriptdump.get.html.ftl | 61 ++ .../org/alfresco/scriptinstall.get.desc.xml | 6 + .../org/alfresco/scriptinstall.get.html.ftl | 33 + .../org/alfresco/scriptinstall.post.desc.xml | 6 + .../org/alfresco/scriptinstall.post.html.ftl | 42 + .../alfresco/templates/webscripts/status.ftl | 52 ++ .../templates/webscripts/xml.status.ftl | 32 + .../web-pagerenderer-application-context.xml | 6 + .../web-scripts-application-context-test.xml | 27 + .../web-scripts-application-context.xml | 345 ++++---- .../repo/web/scripts/RepositoryContainer.java | 250 ------ .../web/scripts/RepositoryImageResolver.java | 50 -- .../scripts/RepositoryScriptProcessor.java | 125 --- .../web/scripts/TestWebScriptRepoServer.java | 159 ---- .../FacebookAuthenticatorFactory.java | 143 ---- .../JSR168PortletAuthenticatorFactory.java | 134 --- .../WebClientPortletAuthenticatorFactory.java | 198 ----- .../scripts/portlet/WebScriptRepoPortlet.java | 33 - .../BasicHttpAuthenticatorFactory.java | 204 ----- .../WebClientAuthenticatorFactory.java | 164 ---- .../servlet/BaseTemplateContentServlet.java | 1 + .../web/app/servlet/PageRendererServlet.java | 87 +- .../app/servlet/PageTemplateProcessor.java | 19 +- .../alfresco/web/bean/ajax/NodeInfoBean.java | 3 + .../alfresco/web/bean/ajax/TaskInfoBean.java | 8 + .../web/config/ServerConfigElement.java | 133 +++ .../web/config/ServerElementReader.java | 83 ++ .../web/scripts/AbstractWebScript.java | 721 ++++++++++++++++ .../web/scripts/BasicHttpAuthenticator.java | 174 ++++ .../alfresco/web/scripts/ClassPathStore.java | 344 ++++++++ .../web/scripts/ClientUrlFunctionMethod.java | 75 ++ .../web/scripts/DeclarativeWebScript.java | 267 ++++++ .../scripts/DeclarativeWebScriptRegistry.java | 788 ++++++++++++++++++ .../org/alfresco/web/scripts/FormData.java | 333 ++++++++ .../org/alfresco/web/scripts/FormatMap.java | 83 ++ .../alfresco/web/scripts/FormatRegistry.java | 158 ++++ .../web/scripts/MultiScriptLoader.java | 66 ++ .../java/org/alfresco/web/scripts/Path.java | 149 ++++ .../{repo => }/web/scripts/RepoStore.java | 28 +- .../alfresco/web/scripts/ScriptLoader.java | 46 + .../alfresco/web/scripts/ScriptProcessor.java | 119 +++ .../alfresco/web/scripts/ScriptUrlMethod.java | 114 +++ .../scripts/ServerModel.java} | 291 ++++--- .../scripts/TemplateProcessor.java} | 423 +++++----- .../web/scripts/TestWebScriptServer.java | 536 ++++++++++++ .../org/alfresco/web/scripts/URLModel.java | 174 ++++ .../web/scripts/WebClientAuthenticator.java | 128 +++ .../org/alfresco/web/scripts/WebScript.java | 53 ++ .../alfresco/web/scripts/WebScriptCache.java | 162 ++++ .../scripts/WebScriptContext.java} | 99 +-- .../web/scripts/WebScriptDescription.java | 196 +++++ .../web/scripts/WebScriptDescriptionImpl.java | 296 +++++++ .../web/scripts/WebScriptException.java | 74 ++ .../alfresco/web/scripts/WebScriptMatch.java | 62 ++ .../alfresco/web/scripts/WebScriptPath.java | 70 ++ .../web/scripts/WebScriptRegistry.java | 120 +++ .../web/scripts/WebScriptRequest.java | 199 +++++ .../web/scripts/WebScriptRequestImpl.java | 151 ++++ .../web/scripts/WebScriptResponse.java | 108 +++ .../web/scripts/WebScriptRuntime.java | 453 ++++++++++ .../web/scripts/WebScriptServlet.java | 132 +++ .../WebScriptServletAuthenticator.java | 48 ++ .../web/scripts/WebScriptServletRequest.java | 357 ++++++++ .../web/scripts/WebScriptServletResponse.java | 218 +++++ .../web/scripts/WebScriptServletRuntime.java | 149 ++++ .../alfresco/web/scripts/WebScriptStatus.java | 178 ++++ .../web/scripts/WebScriptStorage.java | 207 +++++ .../alfresco/web/scripts/WebScriptStore.java | 114 +++ .../web/scripts/WebScriptURLRequest.java | 248 ++++++ .../web/scripts/bean/ContentGet.java | 76 +- .../org/alfresco/web/scripts/bean/Index.java | 56 ++ .../web/scripts/bean/IndexPackage.java | 74 ++ .../alfresco/web/scripts/bean/IndexURI.java | 74 ++ .../web/scripts/bean/IndexUpdate.java | 90 ++ .../web/scripts/bean/JavascriptDebugger.java | 6 +- .../scripts/bean/JavascriptDebuggerPost.java | 6 +- .../web/scripts/bean/KeywordSearch.java | 51 +- .../{repo => }/web/scripts/bean/Login.java | 6 +- .../web/scripts/bean/LoginTicket.java | 6 +- .../web/scripts/bean/LoginTicketDelete.java | 6 +- .../web/scripts/bean/SearchEngines.java | 6 +- .../web/scripts/bean/SearchProxy.java | 4 +- .../web/scripts/bean/ServiceDescription.java | 97 +++ .../web/scripts/bean/ServiceDump.java | 192 +++++ .../web/scripts/bean/ServiceInstall.java | 245 ++++++ .../scripts/facebook/FacebookAPIRuntime.java | 71 ++ .../scripts/facebook/FacebookAPIServlet.java | 74 ++ .../scripts/facebook/FacebookAppModel.java | 89 ++ .../facebook/FacebookAuthenticator.java | 110 +++ .../web/scripts/facebook/FacebookError.java | 54 ++ .../web/scripts/facebook/FacebookModel.java | 249 ++++++ .../web/scripts/facebook/FacebookService.java | 164 ++++ .../web/scripts/facebook/FacebookServlet.java | 75 ++ .../facebook/FacebookServletRequest.java | 172 ++++ .../facebook/FacebookServletRuntime.java | 117 +++ .../alfresco/web/scripts/jsf/UIWebScript.java | 334 ++++++++ .../web/scripts/jsf/WebScriptJSFRequest.java | 111 +++ .../web/scripts/jsf/WebScriptJSFResponse.java | 177 ++++ .../web/scripts/jsf/WebScriptTag.java | 103 +++ .../web/ui/common/ConstantMethodBinding.java | 74 ++ .../component/SelfRenderingComponent.java | 69 ++ .../web/ui/common/tag/BaseComponentTag.java | 229 +++++ .../web/ui/repo/component/UIOpenSearch.java | 2 +- source/web/WEB-INF/web.xml | 1 - 120 files changed, 12732 insertions(+), 2228 deletions(-) create mode 100644 config/alfresco/messages/webscripts-test-help.txt create mode 100644 config/alfresco/messages/webscripts.properties create mode 100644 config/alfresco/templates/webscripts/fbml.status.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/index.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/index.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/index.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/index.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexall.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexall.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexall.get.mediawiki.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexuri.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/indexuri.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptdescription.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.html.ftl create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.desc.xml create mode 100644 config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.html.ftl create mode 100644 config/alfresco/templates/webscripts/status.ftl create mode 100644 config/alfresco/templates/webscripts/xml.status.ftl create mode 100644 config/alfresco/web-scripts-application-context-test.xml delete mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java delete mode 100644 source/java/org/alfresco/repo/web/scripts/servlet/WebClientAuthenticatorFactory.java create mode 100644 source/java/org/alfresco/web/config/ServerConfigElement.java create mode 100644 source/java/org/alfresco/web/config/ServerElementReader.java create mode 100644 source/java/org/alfresco/web/scripts/AbstractWebScript.java create mode 100644 source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/ClassPathStore.java create mode 100644 source/java/org/alfresco/web/scripts/ClientUrlFunctionMethod.java create mode 100644 source/java/org/alfresco/web/scripts/DeclarativeWebScript.java create mode 100644 source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java create mode 100644 source/java/org/alfresco/web/scripts/FormData.java create mode 100644 source/java/org/alfresco/web/scripts/FormatMap.java create mode 100644 source/java/org/alfresco/web/scripts/FormatRegistry.java create mode 100644 source/java/org/alfresco/web/scripts/MultiScriptLoader.java create mode 100644 source/java/org/alfresco/web/scripts/Path.java rename source/java/org/alfresco/{repo => }/web/scripts/RepoStore.java (93%) create mode 100644 source/java/org/alfresco/web/scripts/ScriptLoader.java create mode 100644 source/java/org/alfresco/web/scripts/ScriptProcessor.java create mode 100644 source/java/org/alfresco/web/scripts/ScriptUrlMethod.java rename source/java/org/alfresco/{repo/web/scripts/RepositoryServerModel.java => web/scripts/ServerModel.java} (57%) rename source/java/org/alfresco/{repo/web/scripts/RepositoryTemplateProcessor.java => web/scripts/TemplateProcessor.java} (68%) create mode 100644 source/java/org/alfresco/web/scripts/TestWebScriptServer.java create mode 100644 source/java/org/alfresco/web/scripts/URLModel.java create mode 100644 source/java/org/alfresco/web/scripts/WebClientAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/WebScript.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptCache.java rename source/java/org/alfresco/{repo/web/scripts/Repository.java => web/scripts/WebScriptContext.java} (65%) create mode 100644 source/java/org/alfresco/web/scripts/WebScriptDescription.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptDescriptionImpl.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptException.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptMatch.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptPath.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptRegistry.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptRequest.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptRequestImpl.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptResponse.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptRuntime.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServlet.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletRequest.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletResponse.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptStatus.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptStorage.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptStore.java create mode 100644 source/java/org/alfresco/web/scripts/WebScriptURLRequest.java rename source/java/org/alfresco/{repo => }/web/scripts/bean/ContentGet.java (82%) create mode 100644 source/java/org/alfresco/web/scripts/bean/Index.java create mode 100644 source/java/org/alfresco/web/scripts/bean/IndexPackage.java create mode 100644 source/java/org/alfresco/web/scripts/bean/IndexURI.java create mode 100644 source/java/org/alfresco/web/scripts/bean/IndexUpdate.java rename source/java/org/alfresco/{repo => }/web/scripts/bean/JavascriptDebugger.java (95%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/JavascriptDebuggerPost.java (95%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/KeywordSearch.java (88%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/Login.java (96%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/LoginTicket.java (96%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/LoginTicketDelete.java (97%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/SearchEngines.java (98%) rename source/java/org/alfresco/{repo => }/web/scripts/bean/SearchProxy.java (99%) create mode 100644 source/java/org/alfresco/web/scripts/bean/ServiceDescription.java create mode 100644 source/java/org/alfresco/web/scripts/bean/ServiceDump.java create mode 100644 source/java/org/alfresco/web/scripts/bean/ServiceInstall.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookError.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookModel.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookService.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java create mode 100644 source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java create mode 100644 source/java/org/alfresco/web/scripts/jsf/UIWebScript.java create mode 100644 source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java create mode 100644 source/java/org/alfresco/web/scripts/jsf/WebScriptJSFResponse.java create mode 100644 source/java/org/alfresco/web/scripts/jsf/WebScriptTag.java create mode 100644 source/java/org/alfresco/web/ui/common/ConstantMethodBinding.java create mode 100644 source/java/org/alfresco/web/ui/common/component/SelfRenderingComponent.java create mode 100644 source/java/org/alfresco/web/ui/common/tag/BaseComponentTag.java diff --git a/config/alfresco/messages/webscripts-test-help.txt b/config/alfresco/messages/webscripts-test-help.txt new file mode 100644 index 0000000000..df8f661c28 --- /dev/null +++ b/config/alfresco/messages/webscripts-test-help.txt @@ -0,0 +1,100 @@ +## +## Meta commands +## + +ok> help + + List this help. + +ok> r + + Repeat last command. + +ok> user [] + + Switch to specified . If is omitted, the currently + selected user is shown. + + A ticket may be specified instead of username. + +ok> quit | exit + + Quit this Web Script server. + +## +## HTTP Requests +## + +ok> get + + Issue a HTTP GET request to the Web Script located at . The response + is dumped to the console. + + URL relative to /alfresco/service + + e.g. get /blog/search?q=tutorial + +ok> put + + Issue a HTTP PUT request to the Web Script located at . The response + is dumped to the console. + + URL relative to /alfresco/service + +ok> post + + Issue a HTTP POST request to the Web Script located at . The response + is dumped to the console. + + URL relative to /alfresco/service + +ok> delete + + Issue a HTTP DELETE request to the Web Script located at . The response + is dumped to the console. + + URL relative to /alfresco/service + +ok> tunnel + + Tunnel a request via POST. + + The actual is encoded as either the URL parameter named alf:method or + the request header named X-HTTP-Method-Override as specified via the + parameter: + + param - encode method as URL parameter + header - encode method in Request Header + + e.g. to tunnel 'get /index' via post (where method is encoded in header) issue + + tunnel header get /index + +## +## Request Header Commands +## + +ok> header + + Show all defined headers. + +ok> var = + + Define or update a header value. + + header name + header value + + e.g. + + header alf-force-success=true + +ok> header = + + Delete an existing header value. + + header name + +## +## end +## diff --git a/config/alfresco/messages/webscripts.properties b/config/alfresco/messages/webscripts.properties new file mode 100644 index 0000000000..fe82a3a1cb --- /dev/null +++ b/config/alfresco/messages/webscripts.properties @@ -0,0 +1,86 @@ +## +## Web Script Response Codes +## +webscript.code.100.name=Continue +webscript.code.100.description=Client can continue. +webscript.code.101.name=Switching Protocols +webscript.code.101.description=The server is switching protocols according to Upgrade header. +webscript.code.200.name=OK +webscript.code.200.description=The request succeeded normally. +webscript.code.201.name=Created +webscript.code.201.description=Request succeeded and created a new resource on the server. +webscript.code.202.name=Accepted +webscript.code.202.description=Request was accepted for processing, but was not completed. +webscript.code.203.name=Non authoritative information +webscript.code.203.description=The meta information presented by the client did not originate from the server. +webscript.code.204.name=No ContentSC_NO_CONTENT +webscript.code.204.description=The request succeeded but that there was no new information to return. +webscript.code.205.name=Reset Content +webscript.code.205.description=The agent SHOULD reset the document view which caused the request to be sent. +webscript.code.206.name=Partial Content +webscript.code.206.description=The server has fulfilled the partial GET request for the resource. +webscript.code.300.name=Multiple Choices +webscript.code.300.description=The requested resource corresponds to any one of a set of representations, each with its own specific location. +webscript.code.301.name=Moved Permanently +webscript.code.301.description=The resource has permanently moved to a new location, and that future references should use a new URI with their requests. +webscript.code.302.name=Moved Temporarily +webscript.code.302.description=The resource has temporarily moved to another location, but that future references should still use the original URI to access the resource. +webscript.code.303.name=See Other +webscript.code.303.description=The response to the request can be found under a different URI. +webscript.code.304.name=Not Modified +webscript.code.304.description=A conditional GET operation found that the resource was available and not modified. +webscript.code.305.name=Use Proxy +webscript.code.305.description=The requested resource MUST be accessed through the proxy given by the Location field. +webscript.code.400.name=Bad Request +webscript.code.400.description=Request sent by the client was syntactically incorrect. +webscript.code.401.name=Unauthorized +webscript.code.401.description=The request requires HTTP authentication. +webscript.code.402.name=Payment Required +webscript.code.402.description=Reserved for future use. +webscript.code.403.name=Forbidden +webscript.code.403.description=Server understood the request but refused to fulfill it. +webscript.code.404.name=Not Found +webscript.code.404.description=Requested resource is not available. +webscript.code.405.name=Method Not Allowed +webscript.code.405.description=The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. +webscript.code.406.name=Not Acceptable +webscript.code.406.description=The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. +webscript.code.407.name=Proxy Authentication Required +webscript.code.407.description=The client MUST first authenticate itself with the proxy. +webscript.code.408.name=Request Timeout +webscript.code.408.description=The client did not produce a request within the time that the server was prepared to wait. +webscript.code.409.name=Conflict +webscript.code.409.description=Request could not be completed due to a conflict with the current state of the resource. +webscript.code.410.name=Gone +webscript.code.410.description=Resource is no longer available at the server and no forwarding address is known. +webscript.code.411.name=Length required +webscript.code.411.description=Request cannot be handled without a defined Content-Length. +webscript.code.412.name=Precondition Failed +webscript.code.412.description=The precondition given in one or more of the request-header fields evaluated to false when it was tested on the server. +webscript.code.413.name=Request Entity Too Large +webscript.code.413.description=The server is refusing to process the request because the request entity is larger than the server is willing or able to process. +webscript.code.414.name=Request URI Too Long +webscript.code.414.description=The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. +webscript.code.415.name=Unsupported Media Type +webscript.code.415.description=The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method. +webscript.code.416.name=Requested Range Not Satisfiable +webscript.code.416.description=The server cannot serve the requested byte range. +webscript.code.417.name=Expectation Failed +webscript.code.417.description=Server could not meet the expectation given in the Expect request header. +webscript.code.500.name=Internal Error +webscript.code.500.description=An error inside the HTTP server which prevented it from fulfilling the request. +webscript.code.501.name=Not Implemented +webscript.code.501.description=The HTTP server does not support the functionality needed to fulfill the request. +webscript.code.502.name=Bad Gateway +webscript.code.502.description=HTTP server received an invalid response from a server it consulted when acting as a proxy or gateway. +webscript.code.503.name=Service Unavailable +webscript.code.503.description=The HTTP server is temporarily overloaded, and unable to handle the request. +webscript.code.504.name=Gateway Timeout +webscript.code.504.description=Server did not receive a timely response from the upstream server while acting as a gateway or proxy. +webscript.code.505.name=HTTP version not supported +webscript.code.505.description=Server does not support or refuses to support the HTTP protocol version that was used in the request message. + +## +## Test Web Script Server Help +## +testserver.help=alfresco/messages/webscripts-test-help.txt diff --git a/config/alfresco/templates/webscripts/fbml.status.ftl b/config/alfresco/templates/webscripts/fbml.status.ftl new file mode 100644 index 0000000000..9a0ba1cf2c --- /dev/null +++ b/config/alfresco/templates/webscripts/fbml.status.ftl @@ -0,0 +1,46 @@ + + +
+ + + + + + +
AlfrescoWeb Script Status ${status.code} - ${status.codeName}
+
+ +
Error:${status.codeName} (${status.code}) - ${status.codeDescription} +
  +
Message:${status.message!"<Not specified>"} + <#if status.exception?exists> +
  + <@recursestack status.exception/> + +
Server:Alfresco ${server.edition} v${server.version} schema ${server.schema} +
Time:${date?datetime} +
  +
+ +
+ + +<#macro recursestack exception> + <#if exception.cause?exists> + <@recursestack exception=exception.cause/> + + Exception:${exception.class.name}<#if exception.message?exists> - ${exception.message} +   + <#if exception.cause?exists == false> + <#list exception.stackTrace as element> + ${element} + + <#else> + ${exception.stackTrace[0]} + +   + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/index.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/index.get.desc.xml new file mode 100644 index 0000000000..0f28256724 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/index.get.desc.xml @@ -0,0 +1,6 @@ + + Web Scripts Home + Web Scripts Home + / + /index + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/index.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/index.get.html.ftl new file mode 100644 index 0000000000..feb805f5e6 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/index.get.html.ftl @@ -0,0 +1,36 @@ + + + + + Web Scripts Home + + + +
+ + + + + + +
AlfrescoWeb Scripts Home
Alfresco ${server.edition} v${server.version} +
${webscripts?size} Web Scripts - Online documentation. +
+
+
+
+ Index + +
Browse all Web Scripts +
Browse by Web Script URL +
Browse by Web Script Package +
+
+
+ Maintenance + +
Alfresco Javascript Debugger +
+ + + + Alfresco Web Scripts Maintenance + + + + + + + + +
AlfrescoAlfresco Web Scripts Maintenance
Alfresco ${server.edition} v${server.version} +
+
+ + +<#list tasks as task> + + +
Maintenance Completed
${task}
+
+
List Web Scripts
+ \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexall.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.desc.xml new file mode 100644 index 0000000000..24202c551c --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.desc.xml @@ -0,0 +1,6 @@ + + All Web Scripts Index + Retrieve an index of all Web Scripts + /index/all + /index/all.mediawiki + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexall.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.html.ftl new file mode 100644 index 0000000000..f689723a65 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.html.ftl @@ -0,0 +1,54 @@ + + + + + Index of All Web Scripts + + + + + + + + +
AlfrescoIndex of All Web Scripts
Alfresco ${server.edition} v${server.version} +
${webscripts?size} Web Scripts +
+
+ +
Back to Web Scripts Home +
+
+ <#macro recursepackage package> + <#if package.scripts?size > 0> + Package:
${package.path}

+ <#list package.scripts as webscript> + <#assign desc = webscript.description> + ${desc.shortName} + + <#list desc.URIs as uri> +
${desc.method} ${url.serviceContext}${uri} + +
+
+ + <#if desc.description??>
Description:${desc.description}<#else> +
Authentication:${desc.requiredAuthentication} +
Transaction:${desc.requiredTransaction} +
Format Style:${desc.formatStyle} +
Default Format:${desc.defaultFormat!"Determined at run-time"} +
+
Id:${desc.id} +
Description:${desc.storePath}/${desc.descPath} +
+
+ + + <#list package.children as childpath> + <@recursepackage package=childpath/> + + + + <@recursepackage package=rootpackage/> + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexall.get.mediawiki.ftl b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.mediawiki.ftl new file mode 100644 index 0000000000..efe51f6c27 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexall.get.mediawiki.ftl @@ -0,0 +1,64 @@ +Back to [[HTTP API]]. + + +'''NOTE: This document describes features to be found in Alfresco v2.1 onwards.''' + + += Introduction = + +Welcome to the reference documentation for the Alfresco [[HTTP API]]. + +This document was generated from the Alfresco Server URL + + GET http://:${url.service} + +on ${date?datetime} using Alfresco v${server.version}. + + += Web Script Reference = + +This section provides technical information for all ${webscripts?size} [[Web Scripts]], organized by Web Script Package. + +Documentation for each Web Script includes: + +* Short Name +* Description +* Available URL templates +* Default [[Web Scripts Framework#HTTP Response Formats|response format]] +* How to specify an alternative response +* Authentication requirements +* Transaction requirements +* Location of Web Script description document + +<#macro recursepackage package> +<#if package.scripts?size > 0> +== Package: ${package.path} == +<#list package.scripts as webscript> +<#assign desc = webscript.description> + +=== ${desc.shortName} === + +<#if desc.description??><#if desc.description?ends_with(".")>${desc.description}<#else>${desc.description}.<#else>[No description supplied] + +<#list desc.URIs as uri> + [http://localhost:8080${url.serviceContext}${uri} ${desc.method} ${url.serviceContext}${uri}] + + +Requirements: +* Default Format: ${desc.defaultFormat!"Determined at run-time"} +* Authentication: ${desc.requiredAuthentication} +* Transaction: ${desc.requiredTransaction} +* Format Style: ${desc.formatStyle} + +Definition: +* Id: ${desc.id} +* Description: ${desc.storePath}/${desc.descPath} + + +<#list package.children as childpath> + + <@recursepackage package=childpath/> + + + +<@recursepackage package=rootpackage/> diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.desc.xml new file mode 100644 index 0000000000..e9ec17f38f --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.desc.xml @@ -0,0 +1,5 @@ + + Web Script Package Index + Provide an index of Web Scripts for the specified Web Script package + /index/package/{package} + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.html.ftl new file mode 100644 index 0000000000..6dfc1aaa69 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexpackage.get.html.ftl @@ -0,0 +1,61 @@ + + + + + Index of Web Scripts Package '${package.path}' + + + + + + + + +
AlfrescoIndex of Web Scripts Package '${package.path}'
Alfresco ${server.edition} v${server.version} +
${package.scripts?size} Web Scripts +
+
+ +
Back to Web Scripts Home + <#if package.parent?exists> +
Up to ${package.parent.path} + +
+
+ <#if package.children?size > 0> + + <@recurseuri package=package/> +
+
+ + <#macro recurseuri package> + <#list package.children as childpath> + <#if childpath.scripts?size > 0> +
${childpath.path} + + <@recurseuri package=childpath/> + + + <#list package.scripts as webscript> + <#assign desc = webscript.description> + ${desc.shortName} + + <#list desc.URIs as uri> +
${desc.method} ${url.serviceContext}${uri} + +
+
+ + <#if desc.description??>
Description:${desc.description}<#else> +
Authentication:${desc.requiredAuthentication} +
Transaction:${desc.requiredTransaction} +
Format Style:${desc.formatStyle} +
Default Format:${desc.defaultFormat!"Determined at run-time"} +
+
Id:${desc.id} +
Description:${desc.storePath}/${desc.descPath} +
+
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.desc.xml new file mode 100644 index 0000000000..59b373972d --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.desc.xml @@ -0,0 +1,6 @@ + + Web Script URI Index + Provide an index of Web Scripts for the specified Web Script URI + /index/uri/{uri} + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.html.ftl new file mode 100644 index 0000000000..c8d20c0a53 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/indexuri.get.html.ftl @@ -0,0 +1,61 @@ + + + + + Index of Web Scripts URI '${uri.path}' + + + + + + + + +
AlfrescoIndex of Web Scripts URI '${uri.path}'
Alfresco ${server.edition} v${server.version} +
${uri.scripts?size} Web Scripts +
+
+ +
Back to Web Scripts Home + <#if uri.parent?exists> +
Up to ${uri.parent.path} + +
+
+ <#if uri.children?size > 0> + + <@recurseuri uri=uri/> +
+
+ + <#macro recurseuri uri> + <#list uri.children as childpath> + <#if childpath.scripts?size > 0> +
${childpath.path} + + <@recurseuri uri=childpath/> + + + <#list uri.scripts as webscript> + <#assign desc = webscript.description> + ${desc.shortName} + + <#list desc.URIs as uri> +
${desc.method} ${url.serviceContext}${uri} + +
+
+ + <#if desc.description??>
Description:${desc.description}<#else> +
Authentication:${desc.requiredAuthentication} +
Transaction:${desc.requiredTransaction} +
Format Style:${desc.formatStyle} +
Default Format:${desc.defaultFormat!"Determined at run-time"} +
+
Id:${desc.id} +
Description:${desc.storePath}/${desc.descPath} +
+
+ + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptdescription.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/scriptdescription.get.desc.xml new file mode 100644 index 0000000000..4818b090c9 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptdescription.get.desc.xml @@ -0,0 +1,6 @@ + + Web Script Description + Retrieve description document for identified Web Script + /description/{serviceId} + argument + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.desc.xml new file mode 100644 index 0000000000..c7924671dd --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.desc.xml @@ -0,0 +1,7 @@ + + Display Web Script + Full inspection of Web Script implementation - useful for diagnostics and download/upload + /script/{serviceId} + argument + admin + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl new file mode 100644 index 0000000000..b1b63dde14 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptdump.get.html.ftl @@ -0,0 +1,61 @@ + + + + + Web Script: ${script.id} + + + + + + + +
Web Script: ${script.id}
Alfresco ${server.edition} v${server.version}
Generated from ${url.full} on ${date?datetime}
+

+ + Script Properties + + + + + + + <#list script.URIs as URI> + + + + + +
Id:${script.id}
Short Name:${script.shortName}
Description:${script.description}
Authentication:${script.requiredAuthentication}
Transaction:${script.requiredTransaction}
Method:${script.method}
URL Template:${URI}
Format Style:${script.formatStyle}
Default Format:${script.defaultFormat!"[undefined}]"}
Implementation:${script_class}
+

+ <#list stores as store> + Store: ${store.path} +

+ + <#if store.files?size == 0> + + <#else> +

+ <#list store.files as file> +

+ + + +
[No implementation files]
File: ${file.path} <#if file.overridden>[overridden]
${file.content?html}
+

+ + + + + + <#list stores as store> + <#list store.files as file> + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.desc.xml new file mode 100644 index 0000000000..164ceedf00 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.desc.xml @@ -0,0 +1,6 @@ + + Web Script Installer Form + Web Script Installer Form + /installer + admin + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.html.ftl new file mode 100644 index 0000000000..07cdd57522 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.get.html.ftl @@ -0,0 +1,33 @@ + + + + + Web Script Installer + + + + + + + + +
AlfrescoWeb Scripts Installer
Alfresco ${server.edition} v${server.version} +

+

+
Web Script: +
+
  +
+ +
  +
  +
To create a Web Script file that can be installed: +
  +
1) Display the full definition of the Web Script via the URL ${url.serviceContext}/script/{scriptid} +
  +
     e.g. to display the "AVM Browse Sample", issue ${url.serviceContext}/script/org/alfresco/sample/avmbrowse.get +
  +
2) Save the the HTML page displayed in step 1 +
+ + diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.desc.xml new file mode 100644 index 0000000000..efbbe293d1 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.desc.xml @@ -0,0 +1,6 @@ + + Install Web Script + Install Web Script + /installer + admin + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.html.ftl b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.html.ftl new file mode 100644 index 0000000000..bb6ba5ccb0 --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/scriptinstall.post.html.ftl @@ -0,0 +1,42 @@ + + + + + Installed Web Script: ${installedScript.id} + + + + +
AlfrescoInstalled Web Script: ${installedScript.id} +
Alfresco ${server.edition} v${server.version} +
${date?datetime} +
+

+ +
Inspect ${installedScript.id} +
Back to Web Scripts Home +
+

+ + Script Properties + + + + + + + <#list installedScript.URIs as URI> + + + + +
Id:${installedScript.id}
Short Name:${installedScript.shortName}
Description:${installedScript.description}
Authentication:${installedScript.requiredAuthentication}
Transaction:${installedScript.requiredTransaction}
Method:${installedScript.method}
URL Template:${URI}
Format Style:${installedScript.formatStyle}
Default Format:${installedScript.defaultFormat}
+

+ + Files Installed + <#list installedFiles as file> +
${file.path}(store: ${file.store}) + +
+ + \ No newline at end of file diff --git a/config/alfresco/templates/webscripts/status.ftl b/config/alfresco/templates/webscripts/status.ftl new file mode 100644 index 0000000000..fd233e2404 --- /dev/null +++ b/config/alfresco/templates/webscripts/status.ftl @@ -0,0 +1,52 @@ + + + + + Web Script Status ${status.code} - ${status.codeName} + + + + + + + + +
AlfrescoWeb Script Status ${status.code} - ${status.codeName}
+
+ +
The Web Script ${url.service} has responded with a status of ${status.code} - ${status.codeName}. +
+
+ +
${status.code} Description: ${status.codeDescription} +
  +
Message:${status.message!"<Not specified>"} + <#if status.exception?exists> +
  + <@recursestack status.exception/> + +
Server:Alfresco ${server.edition} v${server.version} schema ${server.schema} +
Time:${date?datetime} +
  + <#if webscript?exists> +
Diagnostics:Inspect Web Script (${webscript.id}) + +
+ + + +<#macro recursestack exception> + <#if exception.cause?exists> + <@recursestack exception=exception.cause/> + +

Exception:${exception.class.name}<#if exception.message?exists> - ${exception.message} +
  + <#if exception.cause?exists == false> + <#list exception.stackTrace as element> +
${element} + + <#else> +
${exception.stackTrace[0]} + +
  + diff --git a/config/alfresco/templates/webscripts/xml.status.ftl b/config/alfresco/templates/webscripts/xml.status.ftl new file mode 100644 index 0000000000..678eb1ca14 --- /dev/null +++ b/config/alfresco/templates/webscripts/xml.status.ftl @@ -0,0 +1,32 @@ + + + + ${status.code} + ${status.codeName} + ${status.codeDescription} + + ${status.message!""} + <#if status.exception?exists>${status.exception.class.name}<#if status.exception.message?exists> - ${status.exception.message} + + <#if status.exception?exists> + <@recursestack status.exception/> + + + Alfresco ${server.edition} v${server.version} schema ${server.schema} + + + +<#macro recursestack exception> + <#if exception.cause?exists> + <@recursestack exception=exception.cause/> + + <#if exception.cause?exists == false> + ${exception} + <#list exception.stackTrace as element> + ${element} + + <#else> + ${exception} + ${exception.stackTrace[0]} + + diff --git a/config/alfresco/web-pagerenderer-application-context.xml b/config/alfresco/web-pagerenderer-application-context.xml index dfd65040a7..e23734930e 100644 --- a/config/alfresco/web-pagerenderer-application-context.xml +++ b/config/alfresco/web-pagerenderer-application-context.xml @@ -19,4 +19,10 @@ + + + + + + diff --git a/config/alfresco/web-scripts-application-context-test.xml b/config/alfresco/web-scripts-application-context-test.xml new file mode 100644 index 0000000000..8ed5ea598b --- /dev/null +++ b/config/alfresco/web-scripts-application-context-test.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + alfresco/messages/webscripts + + + + + + + \ No newline at end of file diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index d22d97034f..65293890e0 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -3,10 +3,156 @@ - - + + + + + + + + + + + + + + + + + + workspace://SpacesStore + /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:extensionwebscripts + + + + true + workspace://SpacesStore + /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:webscripts + + + + alfresco/extension/templates/webscripts + + + + true + alfresco/templates/webscripts + + + + + + + + + + + + + + + + alfresco.messages.webscripts + + + + + + + + + + + ${spaces.store} + /${spaces.company_home.childname} + + + + + + + + + + + + + + + + + + + + + webscript_default + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/html + text/plain + text/xml + application/atom+xml + application/rss+xml + application/json + application/opensearchdescription+xml + text/plain + text/html + text/html + + + + + + + MSIE + + + text/xml + text/xml + text/xml + + + + + + - + @@ -23,193 +169,100 @@ - - - - - - - - - - - - - - - alfresco/messages/webscripts - - - - - - - - - - - - - - - - - - - - - - - workspace://SpacesStore - /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:extensionwebscripts - - - - true - workspace://SpacesStore - /${spaces.company_home.childname}/${spaces.dictionary.childname}/cm:webscripts - - - - alfresco/extension/templates/webscripts - - - - true - alfresco/templates/webscripts - - - - - - - - - - - - - - - - + + + - - - - - - - - ${spaces.store} - /${spaces.company_home.childname} - - - - - - - - - - - - - - - - - Repository - - - - - - - - + + + + + + - - - - - - - - - + + + + + + - - - - - - - + + + + + + + + + + + + + + + + - - + + + + + + - - - + + + + - + - + - + - + - + - + - + - - - + - - - - - - - - + diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java b/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java deleted file mode 100644 index 78ce2a4045..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java +++ /dev/null @@ -1,250 +0,0 @@ -package org.alfresco.repo.web.scripts; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.TemplateService; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.descriptor.DescriptorService; -import org.alfresco.web.scripts.AbstractRuntimeContainer; -import org.alfresco.web.scripts.Authenticator; -import org.alfresco.web.scripts.Description; -import org.alfresco.web.scripts.ServerModel; -import org.alfresco.web.scripts.WebScript; -import org.alfresco.web.scripts.WebScriptException; -import org.alfresco.web.scripts.WebScriptRequest; -import org.alfresco.web.scripts.WebScriptResponse; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.Description.RequiredTransaction; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - - -public class RepositoryContainer extends AbstractRuntimeContainer -{ - // Logger - protected static final Log logger = LogFactory.getLog(RepositoryContainer.class); - - /** Component Dependencies */ - private Repository repository; - private RepositoryImageResolver imageResolver; - private RetryingTransactionHelper retryingTransactionHelper; - private AuthorityService authorityService; - private PermissionService permissionService; - private DescriptorService descriptorService; - - - public void setRepository(Repository repository) - { - this.repository = repository; - } - - public void setRepositoryImageResolver(RepositoryImageResolver imageResolver) - { - this.imageResolver = imageResolver; - } - - public void setPermissionService(PermissionService permissionService) - { - this.permissionService = permissionService; - } - - public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) - { - this.retryingTransactionHelper = retryingTransactionHelper; - } - - public void setDescriptorService(DescriptorService descriptorService) - { - this.descriptorService = descriptorService; - } - - public void setAuthorityService(AuthorityService authorityService) - { - this.authorityService = authorityService; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.Container#getDescription() - */ - public ServerModel getDescription() - { - return new RepositoryServerModel(descriptorService.getServerDescriptor()); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getScriptParameters() - */ - public Map getScriptParameters() - { - Map params = new HashMap(); - params.putAll(super.getScriptParameters()); - addRepoParameters(params); - return params; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.AbstractRuntimeContainer#getTemplateParameters() - */ - public Map getTemplateParameters() - { - Map params = new HashMap(); - params.putAll(super.getTemplateParameters()); - params.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver.getImageResolver()); - addRepoParameters(params); - return params; - } - - /** - * Add Repository specific parameters - * - * @param params - */ - private void addRepoParameters(Map params) - { - if (AlfrescoTransactionSupport.getTransactionId() != null) - { - NodeRef rootHome = repository.getRootHome(); - if (rootHome != null && permissionService.hasPermission(rootHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) - { - params.put("roothome", rootHome); - } - NodeRef companyHome = repository.getCompanyHome(); - if (companyHome != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) - { - params.put("companyhome", companyHome); - } - NodeRef person = repository.getPerson(); - if (person != null && permissionService.hasPermission(companyHome, PermissionService.READ).equals(AccessStatus.ALLOWED)) - { - params.put("person", person); - params.put("userhome", repository.getUserHome(person)); - } - } - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.RuntimeContainer#executeScript(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse, org.alfresco.web.scripts.Authenticator) - */ - public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, Authenticator auth) - throws IOException - { - WebScript script = scriptReq.getServiceMatch().getWebScript(); - Description desc = script.getDescription(); - RequiredAuthentication required = desc.getRequiredAuthentication(); - boolean isGuest = scriptReq.isGuest(); - - if (required == RequiredAuthentication.none) - { - AuthenticationUtil.clearCurrentSecurityContext(); - transactionedExecute(script, scriptReq, scriptRes); - } - else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest) - { - throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "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 - // - if (auth == null || auth.authenticate(required, isGuest)) - { - if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority()) - { - throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access."); - } - - // Execute Web Script - transactionedExecute(script, 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 script within required level of transaction - * - * @param scriptReq - * @param scriptRes - * @throws IOException - */ - protected void transactionedExecute(final WebScript script, final WebScriptRequest scriptReq, final WebScriptResponse scriptRes) - throws IOException - { - final Description description = script.getDescription(); - if (description.getRequiredTransaction() == RequiredTransaction.none) - { - script.execute(scriptReq, scriptRes); - } - else - { - // encapsulate script within transaction - RetryingTransactionCallback work = new RetryingTransactionCallback() - { - public Object execute() throws Exception - { - if (logger.isDebugEnabled()) - logger.debug("Begin transaction: " + description.getRequiredTransaction()); - - script.execute(scriptReq, scriptRes); - - if (logger.isDebugEnabled()) - logger.debug("End transaction: " + description.getRequiredTransaction()); - - return null; - } - }; - - if (description.getRequiredTransaction() == RequiredTransaction.required) - { - retryingTransactionHelper.doInTransaction(work); - } - else - { - retryingTransactionHelper.doInTransaction(work, false, true); - } - } - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java b/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java deleted file mode 100644 index c2265b54c6..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryImageResolver.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.alfresco.repo.web.scripts; - -import javax.servlet.ServletContext; - -import org.alfresco.service.cmr.repository.FileTypeImageSize; -import org.alfresco.service.cmr.repository.TemplateImageResolver; -import org.alfresco.web.ui.common.Utils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.web.context.ServletContextAware; - - -public class RepositoryImageResolver - implements ServletContextAware, InitializingBean -{ - private ServletContext servletContext; - private TemplateImageResolver imageResolver; - - - /* (non-Javadoc) - * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext) - */ - public void setServletContext(ServletContext context) - { - this.servletContext = context; - } - - /*(non-Javadoc) - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - public void afterPropertiesSet() - throws Exception - { - this.imageResolver = new TemplateImageResolver() - { - public String resolveImagePathForName(String filename, FileTypeImageSize size) - { - return Utils.getFileTypeImage(servletContext, filename, size); - } - }; - } - - /** - * @return image resolver - */ - public TemplateImageResolver getImageResolver() - { - return this.imageResolver; - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java b/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java deleted file mode 100644 index 150e092f50..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryScriptProcessor.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.alfresco.repo.web.scripts; - -import java.io.InputStream; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.service.cmr.repository.ScriptException; -import org.alfresco.service.cmr.repository.ScriptLocation; -import org.alfresco.service.cmr.repository.ScriptService; -import org.alfresco.web.scripts.MultiScriptLoader; -import org.alfresco.web.scripts.ScriptContent; -import org.alfresco.web.scripts.ScriptLoader; -import org.alfresco.web.scripts.ScriptProcessor; -import org.alfresco.web.scripts.SearchPath; -import org.alfresco.web.scripts.Store; -import org.alfresco.web.scripts.WebScriptException; -import org.springframework.beans.factory.InitializingBean; - - -public class RepositoryScriptProcessor implements ScriptProcessor, InitializingBean -{ - // dependencies - protected ScriptService scriptService; - protected ScriptLoader scriptLoader; - protected SearchPath searchPath; - - - /** - * Sets the script service - * - * @param scriptService - */ - public void setScriptService(ScriptService scriptService) - { - this.scriptService = scriptService; - } - - public void setSearchPath(SearchPath searchPath) - { - this.searchPath = searchPath; - } - - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ScriptProcessor#findScript(java.lang.String) - */ - public ScriptContent findScript(String path) - { - return scriptLoader.getScript(path); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(java.lang.String, java.util.Map) - */ - public Object executeScript(String path, Map model) - throws ScriptException - { - // locate script within web script stores - ScriptContent scriptContent = findScript(path); - if (scriptContent == null) - { - throw new WebScriptException("Unable to locate script " + path); - } - // execute script - return executeScript(scriptContent, model); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(org.alfresco.web.scripts.ScriptContent, java.util.Map) - */ - public Object executeScript(ScriptContent content, Map model) - { - return scriptService.executeScript("javascript", new RepositoryScriptLocation(content), model); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ScriptProcessor#reset() - */ - public void reset() - { - // NOOP - } - - - private static class RepositoryScriptLocation implements ScriptLocation - { - private ScriptContent content; - - private RepositoryScriptLocation(ScriptContent content) - { - this.content = content; - } - - public InputStream getInputStream() - { - return content.getInputStream(); - } - - public Reader getReader() - { - return content.getReader(); - } - } - - /** - * Register script loader from each Web Script Store with Script Processor - */ - public void afterPropertiesSet() - { - List loaders = new ArrayList(); - for (Store apiStore : searchPath.getStores()) - { - ScriptLoader loader = apiStore.getScriptLoader(); - if (loader == null) - { - throw new WebScriptException("Unable to retrieve script loader for Web Script store " + apiStore.getBasePath()); - } - loaders.add(loader); - } - scriptLoader = new MultiScriptLoader(loaders.toArray(new ScriptLoader[loaders.size()])); - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java b/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java deleted file mode 100644 index 5eec28b5a1..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/TestWebScriptRepoServer.java +++ /dev/null @@ -1,159 +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.repo.web.scripts; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.alfresco.repo.security.authentication.AuthenticationException; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.web.scripts.TestWebScriptServer; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - - -/** - * Stand-alone Web Script Test Server - * - * @author davidc - */ -public class TestWebScriptRepoServer extends TestWebScriptServer -{ - private RetryingTransactionHelper retryingTransactionHelper; - private AuthenticationService authenticationService; - - - /** - * Sets helper that provides transaction callbacks - */ - public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) - { - this.retryingTransactionHelper = retryingTransactionHelper; - } - - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - /** - * Main entry point. - */ - public static void main(String[] args) - { - try - { - TestWebScriptServer testServer = getTestServer(); - testServer.rep(); - } - catch(Throwable e) - { - StringWriter strWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(strWriter); - e.printStackTrace(printWriter); - System.out.println(strWriter.toString()); - } - finally - { - System.exit(0); - } - } - - /** - * Retrieve an instance of the TestWebScriptServer - * - * @return Test Server - */ - public static TestWebScriptServer getTestServer() - { - String[] CONFIG_LOCATIONS = new String[] - { - "classpath:alfresco/application-context.xml", - "classpath:alfresco/web-framework-application-context.xml", - "classpath:alfresco/web-scripts-application-context.xml", - "classpath:alfresco/web-client-application-context.xml" - }; - ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); - TestWebScriptServer testServer = (TestWebScriptRepoServer)context.getBean("webscripts.test"); - return testServer; - } - - /** - * Interpret a single command using the BufferedReader passed in for any data needed. - * - * @param line The unparsed command - * @return The textual output of the command. - */ - @Override - protected String interpretCommand(final String line) - throws IOException - { - try - { - if (username.startsWith("TICKET_")) - { - try - { - retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() - { - public Object execute() throws Exception - { - authenticationService.validate(username); - return null; - } - }); - return executeCommand(line); - } - finally - { - authenticationService.clearCurrentSecurityContext(); - } - } - } - catch(AuthenticationException e) - { - executeCommand("user admin"); - } - - // execute command in context of currently selected user - return AuthenticationUtil.runAs(new RunAsWork() - { - @SuppressWarnings("synthetic-access") - public String doWork() throws Exception - { - return executeCommand(line); - } - }, username); - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java deleted file mode 100644 index 1227c921fb..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/facebook/FacebookAuthenticatorFactory.java +++ /dev/null @@ -1,143 +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.repo.web.scripts.facebook; - -import java.io.IOException; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.web.scripts.Authenticator; -import org.alfresco.web.scripts.WebScriptException; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.facebook.FacebookServletRequest; -import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory; -import org.alfresco.web.scripts.servlet.WebScriptServletRequest; -import org.alfresco.web.scripts.servlet.WebScriptServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -public class FacebookAuthenticatorFactory implements ServletAuthenticatorFactory -{ - // Logger - private static final Log logger = LogFactory.getLog(FacebookAuthenticator.class); - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ - public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res) - { - if (!(req instanceof FacebookServletRequest)) - { - throw new WebScriptException("Facebook request is required; instead a " + req.getClass().getName() + " has been provided"); - } - return new FacebookAuthenticator((FacebookServletRequest)req, res); - } - - - /** - * Web Script Authenticator that supports Facebook authentication - * mechanism. - * - * Upon success, the request is authenticated as the Facebook User Id. - * - * @author davidc - */ - public class FacebookAuthenticator implements Authenticator - { - - // FBML for Facebook login redirect - private static final String LOGIN_REDIRECT = ""; - - - // dependencies - private FacebookServletRequest fbReq; - private WebScriptServletResponse fbRes; - - /** - * Construct - * - * @param authenticationService - * @param req - * @param res - */ - public FacebookAuthenticator(FacebookServletRequest req, WebScriptServletResponse res) - { - this.fbReq = req; - this.fbRes = res; - } - - /* (non-Javadoc) - * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) - */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest) - { - String sessionKey = fbReq.getSessionKey(); - String user = fbReq.getUserId(); - - if (logger.isDebugEnabled()) - { - logger.debug("fb_sig_session_key = '" + sessionKey + "'"); - logger.debug("fb_sig_user = '" + user + "'"); - } - - if ((sessionKey == null || sessionKey.length() == 0) || (user == null || user.length() == 0)) - { - // session has not been established, redirect to login - - String apiKey = fbReq.getApiKey(); - String canvas = (fbReq.isInCanvas()) ? "&canvas" : ""; - - if (logger.isDebugEnabled()) - { - logger.debug("fb_sig_api_key = '" + apiKey + "'"); - logger.debug("fb_sig_in_canvas = '" + canvas + "'"); - } - - try - { - String redirect = String.format(LOGIN_REDIRECT, apiKey, canvas); - - if (logger.isDebugEnabled()) - logger.debug("Facebook session not established; redirecting via " + redirect); - - fbRes.getWriter().write(redirect); - } - catch (IOException e) - { - throw new WebScriptException("Redirect to login failed", e); - } - return false; - } - - if (logger.isDebugEnabled()) - logger.debug("Facebook session established; authenticating as user " + user); - - // session has been established, authenticate as Facebook user id - AuthenticationUtil.setCurrentUser(user); - return true; - } - } - -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java deleted file mode 100644 index b612d38422..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/portlet/JSR168PortletAuthenticatorFactory.java +++ /dev/null @@ -1,134 +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.repo.web.scripts.portlet; - -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.servlet.http.HttpServletResponse; - -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.web.scripts.Authenticator; -import org.alfresco.web.scripts.WebScriptException; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory; -import org.alfresco.web.scripts.portlet.WebScriptPortletRequest; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -public class JSR168PortletAuthenticatorFactory implements PortletAuthenticatorFactory -{ - // Logger - private static final Log logger = LogFactory.getLog(JSR168PortletAuthenticatorFactory.class); - - // dependencies - private AuthenticationService authenticationService; - - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory#create(javax.portlet.RenderRequest, javax.portlet.RenderResponse) - */ - public Authenticator create(RenderRequest req, RenderResponse res) - { - return new JSR168PortletAuthenticator(req, res); - } - - - /** - * Portlet authenticator - * - * @author davidc - */ - public class JSR168PortletAuthenticator implements Authenticator - { - // dependencies - private RenderRequest req; - private RenderResponse res; - - /** - * Construct - * - * @param authenticationService - * @param req - * @param res - */ - public JSR168PortletAuthenticator(RenderRequest req, RenderResponse res) - { - this.req = req; - this.res = res; - } - - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.portlet.WebScriptPortletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.portlet.RenderRequest, javax.portlet.RenderResponse) - */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest) - { - // first look for the username key in the session - we add this by hand for some portals - // when the WebScriptPortletRequest is created - String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME); - if (portalUser == null) - { - 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()); - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as user " + portalUser); - - if (!authenticationService.authenticationExists(portalUser)) - { - throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "User " + portalUser + " is not a known Alfresco user"); - } - AuthenticationUtil.setCurrentUser(portalUser); - } - - return true; - } - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java deleted file mode 100644 index 5d3ef1fb8a..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/portlet/WebClientPortletAuthenticatorFactory.java +++ /dev/null @@ -1,198 +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.repo.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.repo.web.scripts.Repository; -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.Authenticator; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory; -import org.alfresco.web.scripts.portlet.WebScriptPortletRequest; -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 WebClientPortletAuthenticatorFactory implements PortletAuthenticatorFactory -{ - // Logger - private static final Log logger = LogFactory.getLog(WebClientPortletAuthenticatorFactory.class); - - // dependencies - private AuthenticationService authenticationService; - private Repository repository; - - /** - * @param authenticationService - */ - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - /** - * @param scriptContext - */ - public void setRepository(Repository repository) - { - this.repository = repository; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.portlet.PortletAuthenticatorFactory#create(javax.portlet.RenderRequest, javax.portlet.RenderResponse) - */ - public Authenticator create(RenderRequest req, RenderResponse res) - { - return new WebClientPortletAuthenticator(req, res); - } - - - public class WebClientPortletAuthenticator implements Authenticator - { - // dependencies - private RenderRequest req; - private RenderResponse res; - - /** - * Construct - * - * @param authenticationService - * @param req - * @param res - */ - public WebClientPortletAuthenticator(RenderRequest req, RenderResponse res) - { - this.req = req; - this.res = res; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean) - */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest) - { - PortletSession session = req.getPortletSession(); - - // first look for the username key in the session - we add this by hand for some portals - // when the WebScriptPortletRequest is created - String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME); - if (portalUser == null) - { - 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); - } - } - - return true; - } - - /** - * 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 = repository.getPerson(); - User user = new User(authenticationService.getCurrentUserName(), authenticationService.getCurrentTicket(), personRef); - NodeRef homeRef = repository.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); - } - } - -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java b/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java deleted file mode 100644 index 97893dec96..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/portlet/WebScriptRepoPortlet.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.alfresco.repo.web.scripts.portlet; - -import java.io.IOException; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.PortletException; -import javax.portlet.PortletSecurityException; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; - -import org.alfresco.web.app.Application; -import org.alfresco.web.scripts.portlet.WebScriptPortlet; - - -public class WebScriptRepoPortlet extends WebScriptPortlet -{ - - @Override - public void processAction(ActionRequest req, ActionResponse res) throws PortletException, PortletSecurityException, IOException - { - Application.setInPortalServer(true); - super.processAction(req, res); - } - - @Override - public void render(RenderRequest req, RenderResponse res) throws PortletException, PortletSecurityException, IOException - { - Application.setInPortalServer(true); - super.render(req, res); - } - -} diff --git a/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java deleted file mode 100644 index d516fa2e4a..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/servlet/BasicHttpAuthenticatorFactory.java +++ /dev/null @@ -1,204 +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.repo.web.scripts.servlet; - -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.Authenticator; -import org.alfresco.web.scripts.WebScriptException; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory; -import org.alfresco.web.scripts.servlet.WebScriptServletRequest; -import org.alfresco.web.scripts.servlet.WebScriptServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -public class BasicHttpAuthenticatorFactory implements ServletAuthenticatorFactory -{ - // Logger - private static Log logger = LogFactory.getLog(BasicHttpAuthenticator.class); - - // Component dependencies - private AuthenticationService authenticationService; - - - public void setAuthenticationService(AuthenticationService authenticationService) - { - this.authenticationService = authenticationService; - } - - - public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res) - { - return new BasicHttpAuthenticator(req, res); - } - - - /** - * HTTP Basic Authentication - * - * @author davidc - */ - public class BasicHttpAuthenticator implements Authenticator - { - // dependencies - private WebScriptServletRequest servletReq; - private WebScriptServletResponse servletRes; - - /** - * Construct - * - * @param authenticationService - * @param req - * @param res - */ - public BasicHttpAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res) - { - this.servletReq = req; - this.servletRes = res; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.Authenticator#authenticate(org.alfresco.web.scripts.Description.RequiredAuthentication, boolean) - */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest) - { - boolean authorized = false; - - // - // validate credentials - // - - HttpServletRequest req = servletReq.getHttpServletRequest(); - HttpServletResponse res = servletRes.getHttpServletResponse(); - String authorization = req.getHeader("Authorization"); - String ticket = req.getParameter("alf_ticket"); - - if (logger.isDebugEnabled()) - { - logger.debug("HTTP Authorization provided: " + (authorization != null && authorization.length() > 0)); - logger.debug("URL ticket provided: " + (ticket != null && ticket.length() > 0)); - } - - // authenticate as guest, if service allows - if (isGuest && RequiredAuthentication.guest == required) - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as Guest"); - - authenticationService.authenticateAsGuest(); - authorized = true; - } - - // authenticate as specified by explicit ticket on url - else if (ticket != null && ticket.length() > 0) - { - try - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating (URL argument) ticket " + ticket); - - // assume a ticket has been passed - authenticationService.validate(ticket); - authorized = true; - } - catch(AuthenticationException e) - { - // failed authentication - } - } - - // 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 (BASIC HTTP) ticket " + parts[0]); - - // assume a ticket has been passed - authenticationService.validate(parts[0]); - authorized = true; - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating (BASIC HTTP) 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\""); - } - return authorized; - } - } - -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/servlet/WebClientAuthenticatorFactory.java b/source/java/org/alfresco/repo/web/scripts/servlet/WebClientAuthenticatorFactory.java deleted file mode 100644 index 0b9e3c4146..0000000000 --- a/source/java/org/alfresco/repo/web/scripts/servlet/WebClientAuthenticatorFactory.java +++ /dev/null @@ -1,164 +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.repo.web.scripts.servlet; - -import java.io.IOException; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -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.Authenticator; -import org.alfresco.web.scripts.WebScriptException; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory; -import org.alfresco.web.scripts.servlet.WebScriptServletRequest; -import org.alfresco.web.scripts.servlet.WebScriptServletResponse; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.web.context.ServletContextAware; - - -public class WebClientAuthenticatorFactory implements ServletAuthenticatorFactory, ServletContextAware -{ - // Logger - private static final Log logger = LogFactory.getLog(WebClientAuthenticator.class); - - // dependencies - private ServletContext context; - - - /* (non-Javadoc) - * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext) - */ - public void setServletContext(ServletContext context) - { - this.context = context; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.servlet.ServletAuthenticatorFactory#create(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ - public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res) - { - return new WebClientAuthenticator(req, res); - } - - - /** - * Alfresco Web Client Authentication - * - * @author davidc - */ - public class WebClientAuthenticator implements Authenticator - { - // dependencies - private WebScriptServletRequest servletReq; - private WebScriptServletResponse servletRes; - - /** - * Construct - * - * @param authenticationService - * @param req - * @param res - */ - public WebClientAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res) - { - this.servletReq = req; - this.servletRes = res; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.WebScriptServletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ - public boolean authenticate(RequiredAuthentication required, boolean isGuest) - { - AuthenticationStatus status = null; - - try - { - // - // validate credentials - // - HttpServletRequest req = servletReq.getHttpServletRequest(); - HttpServletResponse res = servletRes.getHttpServletResponse(); - String ticket = req.getParameter("ticket"); - - if (logger.isDebugEnabled()) - { - 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, req, res, ticket); - } - else - { - if (isGuest && RequiredAuthentication.guest == required) - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating as Guest"); - - status = AuthenticationHelper.authenticate(context, req, res, true); - } - else - { - if (logger.isDebugEnabled()) - logger.debug("Authenticating session"); - - status = AuthenticationHelper.authenticate(context, req, res, false, false); - } - } - - // - // if not authorized, redirect to login page - // - 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(req, res, context); - } - } - catch(IOException e) - { - throw new WebScriptException("Failed to authenticate", e); - } - - return !(status == null || status == AuthenticationStatus.Failure); - } - } - -} \ No newline at end of file diff --git a/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java b/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java index 4c34fc34cf..20bbabd02f 100644 --- a/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java +++ b/source/java/org/alfresco/web/app/servlet/BaseTemplateContentServlet.java @@ -38,6 +38,7 @@ import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.repo.template.AbsoluteUrlMethod; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.FileTypeImageSize; import org.alfresco.service.cmr.repository.NodeRef; diff --git a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java index 797cf8bdeb..47d8083999 100644 --- a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java +++ b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java @@ -51,23 +51,22 @@ import org.alfresco.config.ConfigService; import org.alfresco.config.JNDIConstants; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.service.ServiceRegistry; +import org.alfresco.repo.template.ClassPathRepoTemplateLoader; import org.alfresco.service.cmr.avm.AVMNotFoundException; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.util.URLEncoder; -import org.alfresco.web.scripts.Cache; -import org.alfresco.web.scripts.Runtime; -import org.alfresco.web.scripts.AbstractRuntime; -import org.alfresco.web.scripts.Authenticator; -import org.alfresco.web.scripts.Match; +import org.alfresco.web.scripts.WebScriptCache; +import org.alfresco.web.scripts.WebScriptMatch; import org.alfresco.web.scripts.WebScriptRequest; -import org.alfresco.web.scripts.WebScriptRequestURLImpl; import org.alfresco.web.scripts.WebScriptResponse; -import org.alfresco.web.scripts.WebScriptResponseImpl; -import org.alfresco.web.scripts.Description.RequiredAuthentication; -import org.alfresco.web.scripts.servlet.WebScriptServlet; +import org.alfresco.web.scripts.WebScriptRuntime; +import org.alfresco.web.scripts.WebScriptServlet; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptServletResponse; +import org.alfresco.web.scripts.WebScriptURLRequest; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Document; @@ -78,6 +77,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import freemarker.cache.MultiTemplateLoader; import freemarker.cache.TemplateLoader; /** @@ -109,7 +109,6 @@ public class PageRendererServlet extends WebScriptServlet // timeout to reload default page cache from private static final int DEFAULT_PAGE_CONFIG_CACHE_TIMEOUT = 30000; - private ServiceRegistry serviceRegistry; private PageTemplateProcessor templateProcessor; private WebScriptTemplateLoader webscriptTemplateLoader; private Map> defaultPageDefMap = null; @@ -121,18 +120,15 @@ public class PageRendererServlet extends WebScriptServlet // init beans ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); - serviceRegistry = (ServiceRegistry)context.getBean("serviceRegistry"); templateProcessor = (PageTemplateProcessor)context.getBean("pagerenderer.templateprocessor"); webscriptTemplateLoader = new WebScriptTemplateLoader(); - - // TODO: Refactor to use web script stores -// ClassPathRepoTemplateLoader repoLoader = new ClassPathRepoTemplateLoader( -// serviceRegistry.getNodeService(), -// serviceRegistry.getContentService(), -// templateProcessor.getDefaultEncoding()); -// templateProcessor.setTemplateLoader(new MultiTemplateLoader(new TemplateLoader[]{ -// webscriptTemplateLoader, repoLoader})); -// templateProcessor.initConfig(); + ClassPathRepoTemplateLoader repoLoader = new ClassPathRepoTemplateLoader( + serviceRegistry.getNodeService(), + serviceRegistry.getContentService(), + templateProcessor.getDefaultEncoding()); + templateProcessor.setTemplateLoader(new MultiTemplateLoader(new TemplateLoader[]{ + webscriptTemplateLoader, repoLoader})); + templateProcessor.initConfig(); // we use a specific config service instance configService = (ConfigService)context.getBean("pagerenderer.config"); @@ -476,7 +472,7 @@ public class PageRendererServlet extends WebScriptServlet /** * WebScript runtime for the PageRenderer servlet. */ - private class PageRendererWebScriptRuntime extends AbstractRuntime + private class PageRendererWebScriptRuntime extends WebScriptRuntime { private PageComponent component; private PageRendererContext context; @@ -488,7 +484,7 @@ public class PageRendererServlet extends WebScriptServlet PageRendererWebScriptRuntime( PageComponent component, PageRendererContext context, String webScript, String executeUrl, String encoding) { - super(PageRendererServlet.this.container); + super(registry, serviceRegistry); this.component = component; this.context = context; this.webScript = webScript; @@ -498,14 +494,6 @@ public class PageRendererServlet extends WebScriptServlet logger.debug("Constructing runtime for url: " + executeUrl); } - /* (non-Javadoc) - * @see org.alfresco.web.scripts.Runtime#getName() - */ - public String getName() - { - return "Page Renderer"; - } - @Override protected String getScriptUrl() { @@ -513,7 +501,7 @@ public class PageRendererServlet extends WebScriptServlet } @Override - protected WebScriptRequest createRequest(Match match) + protected WebScriptRequest createRequest(WebScriptMatch match) { // set the component properties as the additional request attributes Map attributes = new HashMap(); @@ -521,7 +509,7 @@ public class PageRendererServlet extends WebScriptServlet // add the "well known" attributes - such as avm store attributes.put("store", this.context.AVMStore); attributes.put("theme", this.context.Theme); - return new WebScriptPageRendererRequest(this, scriptUrl, match, attributes); + return new WebScriptPageRendererRequest(scriptUrl, match, attributes); } @Override @@ -534,7 +522,7 @@ public class PageRendererServlet extends WebScriptServlet this.baOut = new ByteArrayOutputStream(4096); BufferedWriter wrOut = new BufferedWriter( encoding == null ? new OutputStreamWriter(baOut) : new OutputStreamWriter(baOut, encoding)); - return new WebScriptPageRendererResponse(this, context, component.Id, wrOut, baOut); + return new WebScriptPageRendererResponse(context, component.Id, wrOut, baOut); } catch (UnsupportedEncodingException err) { @@ -542,6 +530,13 @@ public class PageRendererServlet extends WebScriptServlet } } + @Override + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) + { + // TODO: what authentication here? + return true; + } + @Override protected String getScriptMethod() { @@ -568,32 +563,21 @@ public class PageRendererServlet extends WebScriptServlet throw new AlfrescoRuntimeException("Unsupported encoding.", err); } } - - @Override - protected Authenticator createAuthenticator() - { - return null; - } - } /** * Simple implementation of a WebScript URL Request for a webscript on the page */ - private class WebScriptPageRendererRequest extends WebScriptRequestURLImpl + private class WebScriptPageRendererRequest extends WebScriptURLRequest { private Map attributes; - WebScriptPageRendererRequest(Runtime runtime, String scriptUrl, Match match, Map attributes) + WebScriptPageRendererRequest(String scriptUrl, WebScriptMatch match, Map attributes) { - super(runtime, scriptUrl, match); + super(scriptUrl, match); this.attributes = attributes; } - // - // TODO: Refactor attribute methods - implement getScriptParameters and getTemplateParameters instead - // - /* (non-Javadoc) * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) */ @@ -632,7 +616,7 @@ public class PageRendererServlet extends WebScriptServlet /** * Implementation of a WebScript Response object for PageRenderer servlet */ - private class WebScriptPageRendererResponse extends WebScriptResponseImpl + private class WebScriptPageRendererResponse implements WebScriptResponse { private Writer outWriter; private OutputStream outStream; @@ -640,9 +624,8 @@ public class PageRendererServlet extends WebScriptServlet private String componentId; public WebScriptPageRendererResponse( - Runtime runtime, PageRendererContext context, String componentId, Writer outWriter, OutputStream outStream) + PageRendererContext context, String componentId, Writer outWriter, OutputStream outStream) { - super(runtime); this.context = context; this.componentId = componentId; this.outWriter = outWriter; @@ -678,7 +661,7 @@ public class PageRendererServlet extends WebScriptServlet // not supported } - public void setCache(Cache cache) + public void setCache(WebScriptCache cache) { // not supported } diff --git a/source/java/org/alfresco/web/app/servlet/PageTemplateProcessor.java b/source/java/org/alfresco/web/app/servlet/PageTemplateProcessor.java index 7efd302a62..944867c8d1 100644 --- a/source/java/org/alfresco/web/app/servlet/PageTemplateProcessor.java +++ b/source/java/org/alfresco/web/app/servlet/PageTemplateProcessor.java @@ -24,8 +24,7 @@ */ package org.alfresco.web.app.servlet; -import org.alfresco.web.scripts.PresentationTemplateProcessor; - +import org.alfresco.web.scripts.TemplateProcessor; /** * Extension to the webscripts TemplateProcessor class to allow the default encoding @@ -33,7 +32,19 @@ import org.alfresco.web.scripts.PresentationTemplateProcessor; * * @author Kevin Roast */ -public class PageTemplateProcessor extends PresentationTemplateProcessor +public class PageTemplateProcessor extends TemplateProcessor { + public String getDefaultEncoding() + { + return this.defaultEncoding; + } -} + /** + * Initialise FreeMarker Configuration + */ + public void initConfig() + { + super.initConfig(); + templateConfig.setTemplateUpdateDelay(0); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/web/bean/ajax/NodeInfoBean.java b/source/java/org/alfresco/web/bean/ajax/NodeInfoBean.java index 48b3bdc3e9..de379d848a 100644 --- a/source/java/org/alfresco/web/bean/ajax/NodeInfoBean.java +++ b/source/java/org/alfresco/web/bean/ajax/NodeInfoBean.java @@ -26,14 +26,17 @@ package org.alfresco.web.bean.ajax; import java.io.IOException; import java.util.Date; +import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; +import org.alfresco.repo.template.AbsoluteUrlMethod; import org.alfresco.repo.template.CropContentMethod; import org.alfresco.repo.template.TemplateNode; +import org.alfresco.repo.template.UrlEncodeMethod; import org.alfresco.service.cmr.repository.FileTypeImageSize; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; diff --git a/source/java/org/alfresco/web/bean/ajax/TaskInfoBean.java b/source/java/org/alfresco/web/bean/ajax/TaskInfoBean.java index cd4e771dec..c4d6374e13 100644 --- a/source/java/org/alfresco/web/bean/ajax/TaskInfoBean.java +++ b/source/java/org/alfresco/web/bean/ajax/TaskInfoBean.java @@ -32,14 +32,22 @@ import java.util.Map; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; +import org.alfresco.repo.template.AbsoluteUrlMethod; +import org.alfresco.repo.template.CropContentMethod; +import org.alfresco.repo.template.TemplateNode; +import org.alfresco.repo.template.UrlEncodeMethod; import org.alfresco.repo.template.Workflow; import org.alfresco.service.cmr.repository.FileTypeImageSize; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.web.app.servlet.BaseTemplateContentServlet; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Bean used by an AJAX control to send information back on the requested workflow task. diff --git a/source/java/org/alfresco/web/config/ServerConfigElement.java b/source/java/org/alfresco/web/config/ServerConfigElement.java new file mode 100644 index 0000000000..1ac4746445 --- /dev/null +++ b/source/java/org/alfresco/web/config/ServerConfigElement.java @@ -0,0 +1,133 @@ +/* + * 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.config; + +import java.util.List; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.element.ConfigElementAdapter; + +/** + * @author David Caruana + */ +public class ServerConfigElement extends ConfigElementAdapter +{ + public static final String CONFIG_ELEMENT_ID = "server"; + + private String scheme = null; + private String hostname = null; + private Integer port = null; + + /** + * Default constructor + */ + public ServerConfigElement() + { + super(CONFIG_ELEMENT_ID); + } + + /** + * Constructor + * + * @param name Name of the element this config element represents + */ + public ServerConfigElement(String name) + { + super(name); + } + + /** + * @see org.alfresco.config.element.ConfigElementAdapter#getChildren() + */ + public List getChildren() + { + throw new ConfigException("Reading the Server config via the generic interfaces is not supported"); + } + + /** + * @see org.alfresco.config.element.ConfigElementAdapter#combine(org.alfresco.config.ConfigElement) + */ + public ConfigElement combine(ConfigElement configElement) + { + ServerConfigElement newElement = (ServerConfigElement)configElement; + ServerConfigElement combinedElement = new ServerConfigElement(); + + combinedElement.setScheme(newElement.getScheme()); + combinedElement.setHostName(newElement.getHostName()); + combinedElement.setPort(newElement.getPort()); + + return combinedElement; + } + + /** + * @return server scheme + */ + public String getScheme() + { + return scheme; + } + + /** + * @param scheme + */ + public void setScheme(String scheme) + { + this.scheme = scheme; + } + + /** + * @return server hostname + */ + public String getHostName() + { + return hostname; + } + + /** + * @param hostname + */ + public void setHostName(String hostname) + { + this.hostname = hostname; + } + + /** + * @return server port + */ + public Integer getPort() + { + return port; + } + + /** + * @param port + */ + public void setPort(Integer port) + { + this.port = port; + } + +} diff --git a/source/java/org/alfresco/web/config/ServerElementReader.java b/source/java/org/alfresco/web/config/ServerElementReader.java new file mode 100644 index 0000000000..b79b653fea --- /dev/null +++ b/source/java/org/alfresco/web/config/ServerElementReader.java @@ -0,0 +1,83 @@ +/* + * 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.config; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.xml.elementreader.ConfigElementReader; +import org.dom4j.Element; + +/** + * @author David Caruana + */ +public class ServerElementReader implements ConfigElementReader +{ + public static final String ELEMENT_SCHEME = "scheme"; + public static final String ELEMENT_HOSTNAME = "hostname"; + public static final String ELEMENT_PORT = "port"; + + /** + * @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element) + */ + @SuppressWarnings("unchecked") + public ConfigElement parse(Element element) + { + ServerConfigElement configElement = new ServerConfigElement(); + + if (element != null) + { + if (ServerConfigElement.CONFIG_ELEMENT_ID.equals(element.getName()) == false) + { + throw new ConfigException("ServerElementReader can only parse config elements of type '" + ServerConfigElement.CONFIG_ELEMENT_ID + "'"); + } + + Element schemeElem = element.element(ELEMENT_SCHEME); + if (schemeElem != null) + { + configElement.setScheme(schemeElem.getTextTrim()); + } + Element hostnameElem = element.element(ELEMENT_HOSTNAME); + if (hostnameElem != null) + { + configElement.setHostName(hostnameElem.getTextTrim()); + } + Element portElem = element.element(ELEMENT_PORT); + if (portElem != null) + { + try + { + Integer port = new Integer(portElem.getTextTrim()); + configElement.setPort(port); + } + catch(NumberFormatException e) + { + throw new ConfigException("Server port is not a number", e); + } + } + } + + return configElement; + } +} diff --git a/source/java/org/alfresco/web/scripts/AbstractWebScript.java b/source/java/org/alfresco/web/scripts/AbstractWebScript.java new file mode 100644 index 0000000000..1d8f65b5e8 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/AbstractWebScript.java @@ -0,0 +1,721 @@ +/* + * 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.Writer; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.jscript.ScriptableHashMap; +import org.alfresco.repo.template.AbsoluteUrlMethod; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; +import org.alfresco.web.scripts.facebook.FacebookModel; +import org.alfresco.web.scripts.facebook.FacebookServletRequest; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Skeleton implementation of a Web Script + * + * @author davidc + */ +public abstract class AbstractWebScript implements WebScript +{ + // Logger + private static final Log logger = LogFactory.getLog(AbstractWebScript.class); + + // dependencies + private WebScriptContext scriptContext; + private WebScriptRegistry scriptRegistry; + private WebScriptDescription description; + private ServiceRegistry serviceRegistry; + private DescriptorService descriptorService; + + // Status Template cache + private Map statusTemplates = new HashMap(); + private ReentrantReadWriteLock statusTemplateLock = new ReentrantReadWriteLock(); + + + // + // Initialisation + // + + /** + * @param scriptContext + */ + final public void setScriptContext(WebScriptContext scriptContext) + { + this.scriptContext = scriptContext; + } + + /** + * @param serviceRegistry + */ + final public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /** + * @param descriptorService + */ + final public void setDescriptorService(DescriptorService descriptorService) + { + this.descriptorService = descriptorService; + } + + /** + * Sets the Service Description + * + * @param description + */ + final public void setDescription(WebScriptDescription description) + { + this.description = description; + } + + /** + * Initialise Web Script + * + * @param scriptRegistry + */ + public void init(WebScriptRegistry scriptRegistry) + { + this.scriptRegistry = scriptRegistry; + this.statusTemplateLock.writeLock().lock(); + try + { + this.statusTemplates.clear(); + } + finally + { + this.statusTemplateLock.writeLock().unlock(); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScript#getDescription() + */ + final public WebScriptDescription getDescription() + { + return this.description; + } + + + // + // Service Implementation Helpers + // + + /** + * Gets the Repository Context + * + * @return repository context + */ + final public WebScriptContext getRepositoryContext() + { + return this.scriptContext; + } + + /** + * Gets the Web Script Registry + * + * @return Web Script Registry + */ + final public WebScriptRegistry getWebScriptRegistry() + { + return this.scriptRegistry; + } + + /** + * Gets the Alfresco Service Registry + * + * @return service registry + */ + final public ServiceRegistry getServiceRegistry() + { + return this.serviceRegistry; + } + + /** + * Gets the Alfresco Descriptor + * + * @return descriptor + */ + final public DescriptorService getDescriptorService() + { + return this.descriptorService; + } + + // + // Scripting Support + // + + /** + * Create a map of arguments from Web Script Request (for scripting) + * + * @param req Web Script Request + * @return argument map + */ + final protected Map createScriptArgs(WebScriptRequest req) + { + Map args = new ScriptableHashMap(); + String[] names = req.getParameterNames(); + for (String name : names) + { + args.put(name, req.getParameter(name)); + } + return args; + } + + /** + * Create a map of arguments from Web Script Request (for templating) + * + * @param req Web Script Request + * @return argument map + */ + final protected Map createTemplateArgs(WebScriptRequest req) + { + Map args = new HashMap(); + String[] names = req.getParameterNames(); + for (String name : names) + { + args.put(name, req.getParameter(name)); + } + return args; + } + + /** + * Create a map of (array) arguments from Web Script Request (for scripting) + * + * @param req Web Script Request + * @return argument map + */ + final protected Map> createScriptArgsM(WebScriptRequest req) + { + Map> args = new ScriptableHashMap>(); + String[] names = req.getParameterNames(); + for (String name : names) + { + ScriptableHashMap values = new ScriptableHashMap(); + int i = 0; + for (String value : req.getParameterValues(name)) + { + values.put(new Integer(i++).toString(), value); + } + args.put(name, values); + } + return args; + } + + /** + * Create a map of (array) arguments from Web Script Request (for scripting) + * + * @param req Web Script Request + * @return argument map + */ + final protected Map createTemplateArgsM(WebScriptRequest req) + { + Map args = new HashMap(); + String[] names = req.getParameterNames(); + for (String name : names) + { + args.put(name, req.getParameterValues(name)); + } + return args; + } + + /** + * Create a model for script usage + * + * @param req web script request + * @param res web script response + * @param customModel custom model entries + * + * @return script model + */ + final protected Map createScriptModel(WebScriptRequest req, WebScriptResponse res, Map customModel) + { + // create script model + Map model = new HashMap(7, 1.0f); + + // add repository context (only if authenticated and transaction enabled) + if (getDescription().getRequiredAuthentication() != RequiredAuthentication.none && + getDescription().getRequiredTransaction() != RequiredTransaction.none) + { + NodeRef rootHome = scriptContext.getRootHome(); + if (rootHome != null) + { + model.put("roothome", rootHome); + } + NodeRef companyHome = scriptContext.getCompanyHome(); + if (companyHome != null) + { + model.put("companyhome", companyHome); + } + NodeRef person = scriptContext.getPerson(); + if (person != null) + { + model.put("person", person); + model.put("userhome", scriptContext.getUserHome(person)); + } + } + + // add web script context + model.put("args", createScriptArgs(req)); + model.put("argsM", createScriptArgsM(req)); + model.put("guest", req.isGuest()); + model.put("url", new URLModel(req)); + model.put("server", new ServerModel(descriptorService.getServerDescriptor())); + + // TODO: Refactor creation of runtime specific parameters with + // Web Script F/W extraction + if (req instanceof WebScriptServletRequest) + { + model.put("formdata", ((WebScriptServletRequest)req).getFormData()); + } + if (req instanceof FacebookServletRequest) + { + model.put("facebook", new FacebookModel(((FacebookServletRequest)req))); + } + + // add custom model + if (customModel != null) + { + model.putAll(customModel); + } + + // return model + return model; + } + + /** + * Create a model for template usage + * + * @param req web script request + * @param res web script response + * @param customModel custom model entries + * + * @return template model + */ + final protected Map createTemplateModel(WebScriptRequest req, WebScriptResponse res, Map customModel) + { + // create template model + Map model = new HashMap(8, 1.0f); + + // add repository context + if (getDescription().getRequiredAuthentication() != RequiredAuthentication.none && + getDescription().getRequiredTransaction() != RequiredTransaction.none) + { + NodeRef rootHome = scriptContext.getRootHome(); + if (rootHome != null) + { + model.put("roothome", rootHome); + } + NodeRef companyHome = scriptContext.getCompanyHome(); + if (companyHome != null) + { + model.put("companyhome", companyHome); + } + NodeRef person = scriptContext.getPerson(); + if (person != null) + { + model.put("person", person); + model.put("userhome", scriptContext.getUserHome(person)); + } + } + + // add web script context + model.put("args", createTemplateArgs(req)); + model.put("argsM", createTemplateArgsM(req)); + model.put("guest", req.isGuest()); + model.put("url", new URLModel(req)); + model.put("webscript", getDescription()); + model.put("server", new ServerModel(descriptorService.getServerDescriptor())); + + // TODO: Refactor creation of runtime specific parameters with + // Web Script F/W extraction + if (req instanceof FacebookServletRequest) + { + model.put("facebook", new FacebookModel(((FacebookServletRequest)req))); + } + + // add template support + model.put("absurl", new AbsoluteUrlMethod(req.getServerPath())); + model.put("scripturl", new ScriptUrlMethod(req, res)); + model.put("clienturlfunction", new ClientUrlFunctionMethod(res)); + model.put("date", new Date()); + model.put(TemplateService.KEY_IMAGE_RESOLVER, getWebScriptRegistry().getTemplateImageResolver()); + + // add custom model + if (customModel != null) + { + model.putAll(customModel); + } + + return model; + } + + /** + * Render a template (identified by path) + * + * @param templatePath template path + * @param model model + * @param writer output writer + */ + final protected void renderTemplate(String templatePath, Map model, Writer writer) + { + long start = System.currentTimeMillis(); + getWebScriptRegistry().getTemplateProcessor().process(templatePath, model, writer); + if (logger.isDebugEnabled()) + logger.debug("Rendered template " + templatePath + " in " + (System.currentTimeMillis() - start) + "ms"); + } + + /** + * Render a template (contents as string) + * @param template the template + * @param model model + * @param writer output writer + */ + final protected void renderString(String template, Map model, Writer writer) + { + getWebScriptRegistry().getTemplateProcessor().processString(template, model, writer); + } + + /** + * Render an explicit response status template + * + * @param req web script request + * @param res web script response + * @param status web script status + * @param format format + * @param model model + * @throws IOException + */ + final protected void sendStatus(WebScriptRequest req, WebScriptResponse res, WebScriptStatus status, WebScriptCache cache, String format, Map model) + throws IOException + { + // locate status template + // NOTE: search order... + // NOTE: package path is recursed to root package + // 1) script located ...ftl + // 2) script located ..status.ftl + // 3) package located /..ftl + // 4) package located /.status.ftl + // 5) default .ftl + // 6) default status.ftl + + int statusCode = status.getCode(); + String statusFormat = (format == null) ? "" : format; + String scriptId = getDescription().getId(); + StatusTemplate template = getStatusTemplate(scriptId, statusCode, statusFormat); + + // render output + String mimetype = getWebScriptRegistry().getFormatRegistry().getMimeType(req.getAgent(), template.format); + if (mimetype == null) + { + throw new WebScriptException("Web Script format '" + template.format + "' is not registered"); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Force success status header in response: " + req.forceSuccessStatus()); + logger.debug("Sending status " + statusCode + " (Template: " + template.path + ")"); + logger.debug("Rendering response: content type=" + mimetype); + } + + res.reset(); + res.setCache(cache); + res.setStatus(req.forceSuccessStatus() ? HttpServletResponse.SC_OK : statusCode); + res.setContentType(mimetype + ";charset=UTF-8"); + renderTemplate(template.path, model, res.getWriter()); + } + + /** + * Find status template + * + * Note: This method caches template search results + * + * @param scriptId + * @param statusCode + * @param format + * @return status template (or null if not found) + */ + private StatusTemplate getStatusTemplate(String scriptId, int statusCode, String format) + { + StatusTemplate statusTemplate = null; + statusTemplateLock.readLock().lock(); + + try + { + String key = statusCode + "." + format; + statusTemplate = statusTemplates.get(key); + if (statusTemplate == null) + { + // Upgrade read lock to write lock + statusTemplateLock.readLock().unlock(); + statusTemplateLock.writeLock().lock(); + + try + { + // Check again + statusTemplate = statusTemplates.get(key); + if (statusTemplate == null) + { + // Locate template in web script store + statusTemplate = getScriptStatusTemplate(scriptId, statusCode, format); + if (statusTemplate == null) + { + WebScriptPath path = getWebScriptRegistry().getPackage(Path.concatPath("/", getDescription().getScriptPath())); + statusTemplate = getPackageStatusTemplate(path, statusCode, format); + if (statusTemplate == null) + { + statusTemplate = getDefaultStatusTemplate(statusCode); + } + } + + if (logger.isDebugEnabled()) + logger.debug("Caching template " + statusTemplate.path + " for web script " + scriptId + " and status " + statusCode + " (format: " + format + ")"); + + statusTemplates.put(key, statusTemplate); + } + } + finally + { + // Downgrade lock to read + statusTemplateLock.readLock().lock(); + statusTemplateLock.writeLock().unlock(); + } + } + return statusTemplate; + } + finally + { + statusTemplateLock.readLock().unlock(); + } + } + + /** + * Find a script specific status template + * + * @param scriptId + * @param statusCode + * @param format + * @return status template (or null, if not found) + */ + private StatusTemplate getScriptStatusTemplate(String scriptId, int statusCode, String format) + { + String path = scriptId + "." + format + "." + statusCode + ".ftl"; + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, format); + } + path = scriptId + "." + format + ".status.ftl"; + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, format); + } + return null; + } + + /** + * Find a package specific status template + * + * @param scriptPath + * @param statusCode + * @param format + * @return status template (or null, if not found) + */ + private StatusTemplate getPackageStatusTemplate(WebScriptPath scriptPath, int statusCode, String format) + { + while(scriptPath != null) + { + String path = Path.concatPath(scriptPath.getPath(), format + "." + statusCode + ".ftl"); + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, format); + } + path = Path.concatPath(scriptPath.getPath(), format + ".status.ftl"); + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, format); + } + scriptPath = scriptPath.getParent(); + } + return null; + } + + /** + * Find default status template + * + * @param statusCode + * @return status template + */ + private StatusTemplate getDefaultStatusTemplate(int statusCode) + { + String path = statusCode + ".ftl"; + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, WebScriptResponse.HTML_FORMAT); + } + path = "status.ftl"; + if (getWebScriptRegistry().getTemplateProcessor().hasTemplate(path)) + { + return new StatusTemplate(path, WebScriptResponse.HTML_FORMAT); + } + throw new WebScriptException("Default status template /status.ftl could not be found"); + } + + /** + * Execute a script + * + * @param location script location + * @param model model + */ + final protected void executeScript(ScriptLocation location, Map model) + { + long start = System.currentTimeMillis(); + getWebScriptRegistry().getScriptProcessor().executeScript(location, model); + if (logger.isDebugEnabled()) + logger.debug("Executed script " + location.toString() + " in " + (System.currentTimeMillis() - start) + "ms"); + } + + /** + * Helper to convert a Web Script Request URL to a Node Ref + * + * 1) Node - {store_type}/{store_id}/{node_id} + * + * Resolve to node via its Node Reference. + * + * 2) Path - {store_type}/{store_id}/{path} + * + * Resolve to node via its display path. + * + * 3) QName - {store_type}/{store_id}/{child_qname_path} TODO: Implement + * + * Resolve to node via its child qname path. + * + * @param referenceType one of node, path or qname + * @return reference array of reference segments (as described above for each reference type) + */ + protected NodeRef findNodeRef(String referenceType, String[] reference) + { + NodeRef nodeRef = null; + + // construct store reference + if (reference.length < 3) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed"); + } + StoreRef storeRef = new StoreRef(reference[0], reference[1]); + NodeService nodeService = serviceRegistry.getNodeService(); + if (nodeService.exists(storeRef)) + { + if (referenceType.equals("node")) + { + NodeRef urlRef = new NodeRef(storeRef, reference[2]); + if (nodeService.exists(urlRef)) + { + nodeRef = urlRef; + } + } + + else if (referenceType.equals("path")) + { + // TODO: Allow a root path to be specified - for now, hard-code to Company Home +// NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + NodeRef rootNodeRef = getRepositoryContext().getCompanyHome(); + if (reference.length == 3) + { + nodeRef = rootNodeRef; + } + else + { + String[] path = new String[reference.length - /*2*/3]; + System.arraycopy(reference, /*2*/3, path, 0, path.length); + + try + { + FileFolderService ffService = serviceRegistry.getFileFolderService(); + FileInfo fileInfo = ffService.resolveNamePath(rootNodeRef, Arrays.asList(path)); + nodeRef = fileInfo.getNodeRef(); + } + catch (FileNotFoundException e) + { + // NOTE: return null node ref + } + } + } + + else + { + // TODO: Implement 'qname' style + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script Node URL specified an invalid reference style of '" + referenceType + "'"); + } + } + + return nodeRef; + } + + + /** + * Status Template + */ + private class StatusTemplate + { + /** + * Construct + * + * @param path + * @param format + */ + private StatusTemplate(String path, String format) + { + this.path = path; + this.format = format; + } + + private String path; + private String format; + } + +} 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..1c00e7937f --- /dev/null +++ b/source/java/org/alfresco/web/scripts/BasicHttpAuthenticator.java @@ -0,0 +1,174 @@ +/* + * 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 boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest preq, WebScriptServletResponse pres) + { + boolean authorized = false; + + // + // validate credentials + // + + HttpServletRequest req = preq.getHttpServletRequest(); + HttpServletResponse res = pres.getHttpServletResponse(); + String authorization = req.getHeader("Authorization"); + String ticket = req.getParameter("alf_ticket"); + + if (logger.isDebugEnabled()) + { + logger.debug("HTTP Authorization provided: " + (authorization != null && authorization.length() > 0)); + logger.debug("URL ticket provided: " + (ticket != null && ticket.length() > 0)); + } + + // authenticate as guest, if service allows + if (isGuest && RequiredAuthentication.guest == required) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + authenticationService.authenticateAsGuest(); + authorized = true; + } + + // authenticate as specified by explicit ticket on url + else if (ticket != null && ticket.length() > 0) + { + try + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating (URL argument) ticket " + ticket); + + // assume a ticket has been passed + authenticationService.validate(ticket); + authorized = true; + } + catch(AuthenticationException e) + { + // failed authentication + } + } + + // 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 (BASIC HTTP) ticket " + parts[0]); + + // assume a ticket has been passed + authenticationService.validate(parts[0]); + authorized = true; + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating (BASIC HTTP) 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\""); + } + return authorized; + } + +} diff --git a/source/java/org/alfresco/web/scripts/ClassPathStore.java b/source/java/org/alfresco/web/scripts/ClassPathStore.java new file mode 100644 index 0000000000..efd1799641 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ClassPathStore.java @@ -0,0 +1,344 @@ +/* + * 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.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import freemarker.cache.FileTemplateLoader; +import freemarker.cache.TemplateLoader; + + +/** + * ClassPath based Web Script Store + * + * @author davidc + */ +public class ClassPathStore implements WebScriptStore, InitializingBean +{ + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + protected boolean mustExist = false; + protected String classPath; + protected File fileDir; + + + /** + * Sets whether the class path must exist + * + * If it must exist, but it doesn't exist, an exception is thrown + * on initialisation of the store + * + * @param mustExist + */ + public void setMustExist(boolean mustExist) + { + this.mustExist = mustExist; + } + + /** + * Sets the class path + * + * @param classPath classpath + */ + public void setClassPath(String classPath) + { + this.classPath = classPath; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() + throws Exception + { + ClassPathResource resource = new ClassPathResource(classPath); + if (resource.exists()) + { + fileDir = resource.getFile(); + } + else if (mustExist) + { + throw new WebScriptException("Web Script Store classpath:" + classPath + " must exist; it was not found"); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#exists() + */ + public boolean exists() + { + return (fileDir != null); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getBasePath() + */ + public String getBasePath() + { + return "classpath:" + classPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getDescriptionDocumentPaths() + */ + public String[] getDescriptionDocumentPaths() + { + String[] paths; + + try + { + int filePathLength = fileDir.getAbsolutePath().length() +1; + List documentPaths = new ArrayList(); + Resource[] resources = resolver.getResources("classpath*:" + classPath + "/**/*.desc.xml"); + for (Resource resource : resources) + { + if (resource instanceof FileSystemResource) + { + String documentPath = resource.getFile().getAbsolutePath().substring(filePathLength); + documentPath = documentPath.replace('\\', '/'); + documentPaths.add(documentPath); + } + } + paths = documentPaths.toArray(new String[documentPaths.size()]); + } + catch(IOException e) + { + // Note: Ignore: no service description documents found + paths = new String[0]; + } + + return paths; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getScriptDocumentPaths(org.alfresco.web.scripts.WebScript) + */ + public String[] getScriptDocumentPaths(WebScript script) + { + String[] paths; + + try + { + int filePathLength = fileDir.getAbsolutePath().length() +1; + List documentPaths = new ArrayList(); + String scriptPaths = script.getDescription().getId() + ".*"; + Resource[] resources = resolver.getResources("classpath*:" + classPath + "/" + scriptPaths); + for (Resource resource : resources) + { + if (resource instanceof FileSystemResource) + { + String documentPath = resource.getFile().getAbsolutePath().substring(filePathLength); + documentPath = documentPath.replace('\\', '/'); + documentPaths.add(documentPath); + } + } + paths = documentPaths.toArray(new String[documentPaths.size()]); + } + catch(IOException e) + { + // Note: Ignore: no service description documents found + paths = new String[0]; + } + + return paths; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#hasDocument(java.lang.String) + */ + public boolean hasDocument(String documentPath) + { + File document = new File(fileDir, documentPath); + return document.exists(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getDescriptionDocument(java.lang.String) + */ + public InputStream getDocument(String documentPath) + throws IOException + { + File document = new File(fileDir, documentPath); + if (!document.exists()) + { + throw new IOException("Document " + documentPath + " does not exist within store " + getBasePath()); + } + return new FileInputStream(document); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#createDocument(java.lang.String, java.lang.String) + */ + public void createDocument(String documentPath, String content) throws IOException + { + File document = new File(fileDir, documentPath); + + // create directory + File path = document.getParentFile(); + path.mkdirs(); + + // create file + if (!document.createNewFile()) + { + throw new IOException("Document " + documentPath + " already exists"); + } + OutputStream output = new FileOutputStream(document); + try + { + PrintWriter writer = new PrintWriter(output); + writer.write(content); + writer.flush(); + } + finally + { + output.flush(); + output.close(); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getTemplateLoader() + */ + public TemplateLoader getTemplateLoader() + { + FileTemplateLoader loader = null; + try + { + loader = new FileTemplateLoader(fileDir); + } + catch (IOException e) + { + // Note: Can't establish loader, so return null + } + return loader; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptStore#getScriptLoader() + */ + public ScriptLoader getScriptLoader() + { + return new ClassPathScriptLoader(); + } + + /** + * Class path based script loader + * + * @author davidc + */ + private class ClassPathScriptLoader implements ScriptLoader + { + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptLoader#getScriptLocation(java.lang.String) + */ + public ScriptLocation getScriptLocation(String path) + { + ScriptLocation location = null; + File scriptPath = new File(fileDir, path); + if (scriptPath.exists()) + { + location = new ClassPathScriptLocation(scriptPath); + } + return location; + } + } + + /** + * Class path script location + * + * @author davidc + */ + private static class ClassPathScriptLocation implements ScriptLocation + { + private File location; + + /** + * Construct + * + * @param location + */ + public ClassPathScriptLocation(File location) + { + this.location = location; + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getInputStream() + */ + public InputStream getInputStream() + { + try + { + return new FileInputStream(location); + } + catch (FileNotFoundException e) + { + throw new WebScriptException("Unable to retrieve input stream for script " + location.getAbsolutePath()); + } + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.ScriptLocation#getReader() + */ + public Reader getReader() + { + try + { + return new InputStreamReader(getInputStream(), "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new AlfrescoRuntimeException("Unsupported Encoding", e); + } + } + + @Override + public String toString() + { + return location.getAbsolutePath(); + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/ClientUrlFunctionMethod.java b/source/java/org/alfresco/web/scripts/ClientUrlFunctionMethod.java new file mode 100644 index 0000000000..e2e27f1ba4 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ClientUrlFunctionMethod.java @@ -0,0 +1,75 @@ +/* + * 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 a client side javascript function to build urls to this service. + * + *

+ * Usage: clientUrlFunction(String funcName) + */ +public final class ClientUrlFunctionMethod implements TemplateMethodModelEx +{ + WebScriptResponse res; + + /** + * Construct + */ + public ClientUrlFunctionMethod(WebScriptResponse res) + { + this.res = res; + } + + + /** + * @see freemarker.template.TemplateMethodModel#exec(java.util.List) + */ + public Object exec(List args) throws TemplateModelException + { + String result = ""; + + if (args.size() != 0) + { + Object arg0 = args.get(0); + if (arg0 instanceof TemplateScalarModel) + { + String arg = ((TemplateScalarModel)arg0).getAsString(); + result = res.getEncodeScriptUrlFunction(arg); + } + } + + return result; + } +} diff --git a/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java b/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java new file mode 100644 index 0000000000..b8bca86968 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java @@ -0,0 +1,267 @@ +/* + * 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.Serializable; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.jscript.ScriptableHashMap; +import org.alfresco.repo.jscript.ValueConverter; +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Script/template driven based implementation of an Web Script + * + * @author davidc + */ +public class DeclarativeWebScript extends AbstractWebScript +{ + // Logger + private static final Log logger = LogFactory.getLog(DeclarativeWebScript.class); + + // Script Context + private String basePath; + private ScriptLocation executeScript; + + // Javascript Converter + private ValueConverter valueConverter = new ValueConverter(); + + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.AbstractWebScript#init(org.alfresco.web.scripts.WebScriptRegistry) + */ + @Override + public void init(WebScriptRegistry apiRegistry) + { + super.init(apiRegistry); + basePath = getDescription().getId(); + + // Test for "execute" script + String scriptPath = basePath + ".js"; + executeScript = getWebScriptRegistry().getScriptProcessor().findScript(scriptPath); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + final public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException + { + // retrieve requested format + String format = req.getFormat(); + if (format == null || format.length() == 0) + { + format = getDescription().getDefaultFormat(); + } + + try + { + // establish mimetype from format + String mimetype = getWebScriptRegistry().getFormatRegistry().getMimeType(req.getAgent(), format); + if (mimetype == null) + { + throw new WebScriptException("Web Script format '" + format + "' is not registered"); + } + + // construct model for script / template + WebScriptStatus status = new WebScriptStatus(); + WebScriptCache cache = new WebScriptCache(getDescription().getRequiredCache()); + Map model = executeImpl(req, status, cache); + if (model == null) + { + model = new HashMap(7, 1.0f); + } + model.put("status", status); + model.put("cache", cache); + + // extract any request attributes and add them to the model - this is useful for requests + // that wish to pass further arbituary data into a webscript model + for (String name : req.getAttributeNames()) + { + model.put(name, req.getAttribute(name)); + } + + // execute script if it exists + if (executeScript != null) + { + if (logger.isDebugEnabled()) + logger.debug("Executing script " + executeScript); + + Map scriptModel = createScriptModel(req, res, model); + // add return model allowing script to add items to template model + Map returnModel = new ScriptableHashMap(); + scriptModel.put("model", returnModel); + executeScript(executeScript, scriptModel); + mergeScriptModelIntoTemplateModel(returnModel, model); + } + + // create model for template rendering + Map templateModel = createTemplateModel(req, res, model); + + // is a redirect to a status specific template required? + if (status.getRedirect()) + { + sendStatus(req, res, status, cache, format, templateModel); + } + else + { + // render output + int statusCode = status.getCode(); + if (statusCode != HttpServletResponse.SC_OK && !req.forceSuccessStatus()) + { + logger.debug("Force success status header in response: " + req.forceSuccessStatus()); + logger.debug("Setting status " + statusCode); + res.setStatus(statusCode); + } + + // apply cache + res.setCache(cache); + + String callback = req.getJSONCallback(); + if (format.equals(WebScriptResponse.JSON_FORMAT) && callback != null) + { + + if (logger.isDebugEnabled()) + logger.debug("Rendering JSON callback response: content type=" + MimetypeMap.MIMETYPE_TEXT_JAVASCRIPT + ", status=" + statusCode + ", callback=" + callback); + + // NOTE: special case for wrapping JSON results in a javascript function callback + res.setContentType(MimetypeMap.MIMETYPE_TEXT_JAVASCRIPT + ";charset=UTF-8"); + res.getOutputStream().write((callback + "(").getBytes()); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Rendering response: content type=" + mimetype + ", status=" + statusCode); + + res.setContentType(mimetype + ";charset=UTF-8"); + } + + // render response according to requested format + renderFormatTemplate(format, templateModel, res.getWriter()); + + if (format.equals(WebScriptResponse.JSON_FORMAT) && callback != null) + { + // NOTE: special case for wrapping JSON results in a javascript function callback + res.getOutputStream().write(")".getBytes()); + } + } + } + catch(Throwable e) + { + if (logger.isInfoEnabled()) + logger.info("Caught exception & redirecting to status template: " + e.getMessage()); + + // extract status code, if specified + int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + if (e instanceof WebScriptException) + { + statusCode = ((WebScriptException)e).getStatus(); + } + + // send status + WebScriptStatus status = new WebScriptStatus(); + status.setCode(statusCode); + status.setMessage(e.getMessage()); + status.setException(e); + WebScriptCache cache = new WebScriptCache(); + cache.setNeverCache(true); + Map customModel = new HashMap(); + customModel.put("status", status); + Map templateModel = createTemplateModel(req, res, customModel); + sendStatus(req, res, status, cache, format, templateModel); + } + } + + /** + * Merge script generated model into template-ready model + * + * @param scriptModel script model + * @param templateModel template model + */ + @SuppressWarnings("unchecked") + final private void mergeScriptModelIntoTemplateModel(Map scriptModel, Map templateModel) + { + for (Map.Entry entry : scriptModel.entrySet()) + { + // retrieve script model value + Object value = entry.getValue(); + Object templateValue = (value instanceof Serializable) ? valueConverter.convertValueForRepo((Serializable)value) : value; + templateModel.put(entry.getKey(), templateValue); + } + } + + /** + * Execute custom Java logic + * + * @param req Web Script request + * @param status Web Script status + * @return custom service model + */ + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + return null; + } + + /** + * Execute custom Java logic + * + * @param req Web Script request + * @param status Web Script status + * @param cache Web Script cache + * @return custom service model + */ + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status, WebScriptCache cache) + { + // NOTE: Redirect to those web scripts implemented before cache support + return executeImpl(req, status); + } + + /** + * Render a template (of given format) to the Web Script Response + * + * @param format template format (null, default format) + * @param model data model to render + * @param writer where to output + */ + final protected void renderFormatTemplate(String format, Map model, Writer writer) + { + format = (format == null) ? "" : format; + String templatePath = basePath + "." + format + ".ftl"; + + if (logger.isDebugEnabled()) + logger.debug("Rendering template '" + templatePath + "'"); + + renderTemplate(templatePath, model, writer); + } + +} diff --git a/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java b/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java new file mode 100644 index 0000000000..9b5dd5a19c --- /dev/null +++ b/source/java/org/alfresco/web/scripts/DeclarativeWebScriptRegistry.java @@ -0,0 +1,788 @@ +/* + * 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.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import javax.servlet.ServletContext; + +import org.alfresco.service.cmr.repository.FileTypeImageSize; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.util.AbstractLifecycleBean; +import org.alfresco.web.scripts.WebScriptDescription.FormatStyle; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.alfresco.web.scripts.WebScriptDescription.RequiredTransaction; +import org.alfresco.web.ui.common.Utils; +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.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.web.context.ServletContextAware; + + +/** + * Registry of declarative (scripted/template driven) Web Scripts + * + * @author davidc + */ +public class DeclarativeWebScriptRegistry extends AbstractLifecycleBean + implements WebScriptRegistry, ServletContextAware, InitializingBean +{ + // Logger + private static final Log logger = LogFactory.getLog(DeclarativeWebScriptRegistry.class); + + private ServletContext servletContext; + private String defaultWebScript; + private FormatRegistry formatRegistry; + private WebScriptStorage storage; + private TemplateImageResolver imageResolver; + + + // map of web scripts by id + // NOTE: The map is sorted by id (ascending order) + private Map webscriptsById = new TreeMap(); + + // map of web scripts by url + // NOTE: The map is sorted by url (descending order) + private Map webscriptsByURL = new TreeMap(Collections.reverseOrder()); + + // map of web script packages by path + private Map packageByPath = new TreeMap(); + + // map of web script uris by path + private Map uriByPath = new TreeMap(); + + + // + // Initialisation + // + + /** + * Sets the available Web Script Stores + * + * @param storage + */ + public void setStorage(WebScriptStorage storage) + { + this.storage = storage; + } + + /** + * Sets the default service implementation bean + * + * @param defaultWebScript + */ + public void setDefaultWebScript(String defaultWebScript) + { + this.defaultWebScript = defaultWebScript; + } + + /** + * Sets the response format registry + * + * @param formatRegistry + */ + public void setFormatRegistry(FormatRegistry formatRegistry) + { + this.formatRegistry = formatRegistry; + } + + /* (non-Javadoc) + * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext) + */ + public void setServletContext(ServletContext context) + { + this.servletContext = context; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception + { + this.imageResolver = new TemplateImageResolver() + { + public String resolveImagePathForName(String filename, FileTypeImageSize size) + { + return Utils.getFileTypeImage(servletContext, filename, size); + } + }; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#reset() + */ + public void reset() + { + long startTime = System.currentTimeMillis(); + try + { + getTemplateProcessor().resetCache(); + getScriptProcessor().resetCache(); + initWebScripts(); + } + finally + { + if (logger.isInfoEnabled()) + logger.info("Registered " + webscriptsById.size() + " Web Scripts, " + webscriptsByURL.size() + " URLs (in " + (System.currentTimeMillis() - startTime) + "ms)"); + } + } + + /* (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onBootstrap(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onBootstrap(ApplicationEvent event) + { + reset(); + } + + /* (non-Javadoc) + * @see org.alfresco.util.AbstractLifecycleBean#onShutdown(org.springframework.context.ApplicationEvent) + */ + @Override + protected void onShutdown(ApplicationEvent event) + { + } + + /** + * Initialise Web Scripts + * + * Note: Each invocation of this method resets the list of the services + */ + private void initWebScripts() + { + if (logger.isDebugEnabled()) + logger.debug("Initialising Web Scripts"); + + // clear currently registered services + webscriptsById.clear(); + webscriptsByURL.clear(); + packageByPath.clear(); + packageByPath.put("/", new Path("/")); + uriByPath.clear(); + uriByPath.put("/", new Path("/")); + + // register services + for (WebScriptStore apiStore : storage.getStores()) + { + if (logger.isDebugEnabled()) + logger.debug("Locating Web Scripts within " + apiStore.getBasePath()); + + String[] serviceDescPaths = apiStore.getDescriptionDocumentPaths(); + for (String serviceDescPath : serviceDescPaths) + { + try + { + // build service description + WebScriptDescription serviceDesc = null; + InputStream serviceDescIS = null; + try + { + serviceDescIS = apiStore.getDocument(serviceDescPath); + serviceDesc = createDescription(apiStore, serviceDescPath, serviceDescIS); + } + catch(IOException e) + { + throw new WebScriptException("Failed to read Web Script description document " + apiStore.getBasePath() + serviceDescPath, e); + } + finally + { + try + { + if (serviceDescIS != null) serviceDescIS.close(); + } + catch(IOException e) + { + // NOTE: ignore close exception + } + } + + // determine if service description has been registered + String id = serviceDesc.getId(); + if (webscriptsById.containsKey(id)) + { + // move to next service + if (logger.isDebugEnabled()) + { + WebScript existingService = webscriptsById.get(id); + WebScriptDescription existingDesc = existingService.getDescription(); + String msg = "Web Script description document " + serviceDesc.getStorePath() + "/" + serviceDesc.getDescPath(); + msg += " overridden by " + existingDesc.getStorePath() + "/" + existingDesc.getDescPath(); + logger.debug(msg); + } + continue; + } + + // construct service implementation + ApplicationContext applicationContext = getApplicationContext(); + String beanName = "webscript." + id.replace('/', '.'); + String serviceImplName = (applicationContext.containsBean(beanName)) ? beanName : defaultWebScript; + AbstractWebScript serviceImpl = (AbstractWebScript)applicationContext.getBean(serviceImplName); + serviceImpl.setDescription(serviceDesc); + serviceImpl.init(this); + + if (logger.isDebugEnabled()) + logger.debug("Found Web Script " + id + " (desc: " + serviceDescPath + ", impl: " + serviceImplName + ", auth: " + + serviceDesc.getRequiredAuthentication() + ", trx: " + serviceDesc.getRequiredTransaction() + ", format style: " + + serviceDesc.getFormatStyle() + ", default format: " + serviceDesc.getDefaultFormat() + ")"); + + // register service and its urls + webscriptsById.put(id, serviceImpl); + for (String uriTemplate : serviceDesc.getURIs()) + { + // establish static part of url template + boolean wildcard = false; + boolean extension = true; + int queryArgIdx = uriTemplate.indexOf('?'); + if (queryArgIdx != -1) + { + uriTemplate = uriTemplate.substring(0, queryArgIdx); + } + int tokenIdx = uriTemplate.indexOf('{'); + if (tokenIdx != -1) + { + uriTemplate = uriTemplate.substring(0, tokenIdx); + wildcard = true; + } + if (serviceDesc.getFormatStyle() != WebScriptDescription.FormatStyle.argument) + { + int extIdx = uriTemplate.lastIndexOf("."); + if (extIdx != -1) + { + uriTemplate = uriTemplate.substring(0, extIdx); + } + extension = false; + } + + // index service by static part of url (ensuring no other service has already claimed the url) + String uriIdx = serviceDesc.getMethod().toString() + ":" + uriTemplate; + if (webscriptsByURL.containsKey(uriIdx)) + { + URLIndex urlIndex = webscriptsByURL.get(uriIdx); + WebScript existingService = urlIndex.script; + if (!existingService.getDescription().getId().equals(serviceDesc.getId())) + { + String msg = "Web Script document " + serviceDesc.getDescPath() + " is attempting to define the url '" + uriIdx + "' already defined by " + existingService.getDescription().getDescPath(); + throw new WebScriptException(msg); + } + } + else + { + URLIndex urlIndex = new URLIndex(uriTemplate, wildcard, extension, serviceImpl); + webscriptsByURL.put(uriIdx, urlIndex); + + if (logger.isDebugEnabled()) + logger.debug("Registered Web Script URL '" + uriIdx + "'"); + } + } + + // build path indexes to web script + registerPackage(serviceImpl); + registerURIs(serviceImpl); + } + catch(WebScriptException e) + { + if (logger.isWarnEnabled()) + { + Throwable c = e; + String cause = c.getMessage(); + while (c.getCause() != null && !c.getCause().equals(c)) + { + c = c.getCause(); + cause += " ; " + c.getMessage(); + } + String msg = "Unable to register script " + apiStore.getBasePath() + "/" + serviceDescPath + " due to error: " + cause; + logger.warn(msg); + } + else + { + throw e; + } + } + } + } + } + + /** + * Register a Web Script Package + * + * @param script + */ + private void registerPackage(WebScript script) + { + WebScriptDescription desc = script.getDescription(); + Path path = packageByPath.get("/"); + String[] parts = desc.getScriptPath().split("/"); + for (String part : parts) + { + Path subpath = packageByPath.get(Path.concatPath(path.getPath(), part)); + if (subpath == null) + { + subpath = path.createChildPath(part); + packageByPath.put(subpath.getPath(), subpath); + } + path = subpath; + } + path.addScript(script); + } + + /** + * Register a Web Script URI + * + * @param script + */ + private void registerURIs(WebScript script) + { + WebScriptDescription desc = script.getDescription(); + for (String uri : desc.getURIs()) + { + Path path = uriByPath.get("/"); + String[] parts = uri.split("/"); + for (String part : parts) + { + if (part.indexOf("?") != -1) + { + part = part.substring(0, part.indexOf("?")); + } + Path subpath = uriByPath.get(Path.concatPath(path.getPath(), part)); + if (subpath == null) + { + subpath = path.createChildPath(part); + uriByPath.put(subpath.getPath(), subpath); + } + path = subpath; + } + path.addScript(script); + } + } + + /** + * Create an Web Script Description + * + * @param store + * @param serviceDescPath + * @param serviceDoc + * + * @return web script service description + */ + private WebScriptDescription createDescription(WebScriptStore store, String serviceDescPath, InputStream serviceDoc) + { + SAXReader reader = new SAXReader(); + try + { + // retrieve script path + int iPathIdx = serviceDescPath.lastIndexOf('/'); + String scriptPath = serviceDescPath.substring(0, iPathIdx == -1 ? 0 : iPathIdx); + + // retrieve script id + String id = serviceDescPath.substring(0, serviceDescPath.lastIndexOf(".desc.xml")); + + // retrieve http method + int methodIdx = id.lastIndexOf('.'); + if (methodIdx == -1 || (methodIdx == id.length() - 1)) + { + throw new WebScriptException("Unable to establish HTTP Method from web script description: naming convention must be ..desc.xml"); + } + String method = id.substring(methodIdx + 1).toUpperCase(); + + // parse description document + Document document = reader.read(serviceDoc); + Element rootElement = document.getRootElement(); + if (!rootElement.getName().equals("webscript")) + { + throw new WebScriptException("Expected root element - found <" + rootElement.getName() + ">"); + } + + // retrieve short name + Element shortNameElement = rootElement.element("shortname"); + if (shortNameElement == null || shortNameElement.getTextTrim() == null || shortNameElement.getTextTrim().length() == 0) + { + throw new WebScriptException("Expected value"); + } + String shortName = shortNameElement.getTextTrim(); + + // retrieve description + String description = null; + Element descriptionElement = rootElement.element("description"); + if (descriptionElement != null) + { + description = descriptionElement.getTextTrim(); + } + + // retrieve urls + List urlElements = rootElement.elements("url"); + if (urlElements == null || urlElements.size() == 0) + { + throw new WebScriptException("Expected at least one element"); + } + List uris = new ArrayList(); + Iterator iterElements = urlElements.iterator(); + while(iterElements.hasNext()) + { + // retrieve url element + Element urlElement = (Element)iterElements.next(); + + // retrieve url template + String template = urlElement.getTextTrim(); + if (template == null || template.length() == 0) + { + // NOTE: for backwards compatibility only + template = urlElement.attributeValue("template"); + if (template == null || template.length() == 0) + { + throw new WebScriptException("Expected element value"); + } + } + uris.add(template); + } + + // retrieve authentication + RequiredAuthentication reqAuth = RequiredAuthentication.none; + Element authElement = rootElement.element("authentication"); + if (authElement != null) + { + String reqAuthStr = authElement.getTextTrim(); + if (reqAuthStr == null || reqAuthStr.length() == 0) + { + throw new WebScriptException("Expected value"); + } + reqAuth = RequiredAuthentication.valueOf(reqAuthStr); + if (reqAuth == null) + { + throw new WebScriptException("Authentication '" + reqAuthStr + "' is not a valid value"); + } + } + + // retrieve transaction + RequiredTransaction reqTrx = (reqAuth == RequiredAuthentication.none) ? RequiredTransaction.none : RequiredTransaction.required; + Element trxElement = rootElement.element("transaction"); + if (trxElement != null) + { + String reqTrxStr = trxElement.getTextTrim(); + if (reqTrxStr == null || reqTrxStr.length() == 0) + { + throw new WebScriptException("Expected value"); + } + reqTrx = RequiredTransaction.valueOf(reqTrxStr); + if (reqTrx == null) + { + throw new WebScriptException("Transaction '" + reqTrxStr + "' is not a valid value"); + } + } + + // retrieve format + String defaultFormat = "html"; + FormatStyle formatStyle = FormatStyle.any; + Element formatElement = rootElement.element("format"); + if (formatElement != null) + { + // establish if default is set explicitly + String attrDefaultValue = formatElement.attributeValue("default"); + if (attrDefaultValue != null) + { + defaultFormat = (attrDefaultValue.length() == 0) ? null : attrDefaultValue; + } + // establish format declaration style + String formatStyleStr = formatElement.getTextTrim(); + if (formatStyleStr != null && formatStyleStr.length() > 0) + { + formatStyle = FormatStyle.valueOf(formatStyleStr); + if (formatStyle == null) + { + throw new WebScriptException("Format Style '" + formatStyle + "' is not a valid value"); + } + } + } + + // retrieve caching + WebScriptCache cache = new WebScriptCache(); + Element cacheElement = rootElement.element("cache"); + if (cacheElement != null) + { + Element neverElement = cacheElement.element("never"); + if (neverElement != null) + { + String neverStr = neverElement.getTextTrim(); + boolean neverBool = (neverStr == null || neverStr.length() == 0) ? true : Boolean.valueOf(neverStr); + cache.setNeverCache(neverBool); + } + Element publicElement = cacheElement.element("public"); + if (publicElement != null) + { + String publicStr = publicElement.getTextTrim(); + boolean publicBool = (publicStr == null || publicStr.length() == 0) ? true : Boolean.valueOf(publicStr); + cache.setIsPublic(publicBool); + } + Element revalidateElement = cacheElement.element("mustrevalidate"); + if (revalidateElement != null) + { + String revalidateStr = revalidateElement.getTextTrim(); + boolean revalidateBool = (revalidateStr == null || revalidateStr.length() == 0) ? true : Boolean.valueOf(revalidateStr); + cache.setMustRevalidate(revalidateBool); + } + } + + // construct service description + WebScriptDescriptionImpl serviceDesc = new WebScriptDescriptionImpl(); + serviceDesc.setStore(store); + serviceDesc.setScriptPath(scriptPath); + serviceDesc.setDescPath(serviceDescPath); + serviceDesc.setId(id); + serviceDesc.setShortName(shortName); + serviceDesc.setDescription(description); + serviceDesc.setRequiredAuthentication(reqAuth); + serviceDesc.setRequiredTransaction(reqTrx); + serviceDesc.setRequiredCache(cache); + serviceDesc.setMethod(method); + serviceDesc.setUris(uris.toArray(new String[uris.size()])); + serviceDesc.setDefaultFormat(defaultFormat); + serviceDesc.setFormatStyle(formatStyle); + return serviceDesc; + } + catch(DocumentException e) + { + throw new WebScriptException("Failed to parse web script description document " + serviceDescPath, e); + } + catch(WebScriptException e) + { + throw new WebScriptException("Failed to parse web script description document " + serviceDescPath, e); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getPackage(java.lang.String) + */ + public WebScriptPath getPackage(String scriptPackage) + { + return packageByPath.get(scriptPackage); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getUri(java.lang.String) + */ + public WebScriptPath getUri(String scriptUri) + { + return uriByPath.get(scriptUri); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getWebScripts() + */ + public Collection getWebScripts() + { + return webscriptsById.values(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getWebScript(java.lang.String) + */ + public WebScript getWebScript(String id) + { + return webscriptsById.get(id); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#findWebScript(java.lang.String, java.lang.String) + */ + public WebScriptMatch findWebScript(String method, String uri) + { + long startTime = System.currentTimeMillis(); + + // TODO: Replace with more efficient approach + String matchedPath = null; + DeclarativeWebScriptMatch apiServiceMatch = null; + String match = method.toString().toUpperCase() + ":" + uri; + String matchNoExt = method.toString().toUpperCase() + ":" + ((uri.indexOf('.') != -1) ? uri.substring(0, uri.indexOf('.')) : uri); + + // locate full match - on URI and METHOD + for (Map.Entry entry : webscriptsByURL.entrySet()) + { + URLIndex urlIndex = entry.getValue(); + String index = entry.getKey(); + String test = urlIndex.includeExtension ? match : matchNoExt; + if ((urlIndex.wildcardPath && test.startsWith(index)) || (!urlIndex.wildcardPath && test.equals(index))) + { + apiServiceMatch = new DeclarativeWebScriptMatch(urlIndex.path, urlIndex.script); + break; + } + else if ((urlIndex.wildcardPath && uri.startsWith(urlIndex.path)) || (!urlIndex.wildcardPath && uri.equals(urlIndex.path))) + { + matchedPath = urlIndex.path; + } + } + + // locate URI match + if (apiServiceMatch == null && matchedPath != null) + { + apiServiceMatch = new DeclarativeWebScriptMatch(matchedPath); + } + + if (logger.isDebugEnabled()) + logger.debug("Web Script index lookup for uri " + uri + " took " + (System.currentTimeMillis() - startTime) + "ms"); + + return apiServiceMatch; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getContext() + */ + public ServletContext getContext() + { + return servletContext; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getFormatRegistry() + */ + public FormatRegistry getFormatRegistry() + { + return this.formatRegistry; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getTemplateProcessor() + */ + public TemplateProcessor getTemplateProcessor() + { + return this.storage.getTemplateProcessor(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getTemplateImageResolver() + */ + public TemplateImageResolver getTemplateImageResolver() + { + return this.imageResolver; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRegistry#getScriptProcessor() + */ + public ScriptProcessor getScriptProcessor() + { + return this.storage.getScriptProcessor(); + } + + /** + * Web Script Match + * + * @author davidc + */ + public static class DeclarativeWebScriptMatch implements WebScriptMatch + { + private String path; + private WebScript service; + private Kind kind; + + /** + * Construct + * + * @param path + * @param service + */ + public DeclarativeWebScriptMatch(String path, WebScript service) + { + this.kind = Kind.FULL; + this.path = path; + this.service = service; + } + + /** + * Construct + * + * @param path + * @param service + */ + public DeclarativeWebScriptMatch(String path) + { + this.kind = Kind.URI; + this.path = path; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptMatch#getKind() + */ + public Kind getKind() + { + return this.kind; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptMatch#getPath() + */ + public String getPath() + { + return path; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptMatch#getWebScript() + */ + public WebScript getWebScript() + { + return service; + } + + @Override + public String toString() + { + return path; + } + } + + /** + * Web Script URL Index Entry + */ + private static class URLIndex + { + private URLIndex(String path, boolean wildcardPath, boolean includeExtension, WebScript script) + { + this.path = path; + this.wildcardPath = wildcardPath; + this.includeExtension = includeExtension; + this.script = script; + } + + private String path; + private boolean wildcardPath; + private boolean includeExtension; + private WebScript script; + } + +} diff --git a/source/java/org/alfresco/web/scripts/FormData.java b/source/java/org/alfresco/web/scripts/FormData.java new file mode 100644 index 0000000000..4bd3fd8bd5 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/FormData.java @@ -0,0 +1,333 @@ +/* + * 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.Serializable; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.jscript.Scopeable; +import org.alfresco.repo.jscript.ScriptNode; +import org.alfresco.repo.jscript.ScriptNode.ScriptContent; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.io.FilenameUtils; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; + + +/** + * Form Data + * + * @author davidc + */ +public class FormData implements Serializable, Scopeable +{ + private static final long serialVersionUID = 1832644544828452385L; + + private Scriptable scope; + private HttpServletRequest req; + private ServletFileUpload upload; + private Map fields = null; + private Map parameters = null; + private Map files = null; + private String encoding = null; + + /** + * Construct + * + * @param req + */ + public FormData(HttpServletRequest req) + { + this.req = req; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) + */ + public void setScope(Scriptable scope) + { + this.scope = scope; + } + + /** + * Determine if multi-part form data has been provided + * + * @return true => multi-part + */ + public boolean getIsMultiPart() + { + return upload.isMultipartContent(req); + } + + /** + * Determine if form data has specified field + * + * @param name field to look for + * @return true => form data contains field + */ + public boolean hasField(String name) + { + Map fields = getFieldsMap(); + return fields.containsKey(name); + } + + /** + * Gets the Form fields + * + * @return array of FormField + */ + public Scriptable getFields() + { + Map fieldsMap = getFieldsMap(); + Object[] fields = new Object[fieldsMap.values().size()]; + fieldsMap.values().toArray(fields); + return Context.getCurrentContext().newArray(this.scope, fields); + } + + /** + * Gets parameters encoded in the form data + * + * @return map (name, value) of parameters + */ + /*package*/ Map getParameters() + { + return getParametersMap(); + } + + /** + * Gets files encoded in form data + * + * @return map (name, ScriptContent) of files + */ + /*package*/ Map getFiles() + { + return getFilesMap(); + } + + /** + * Helper to parse servlet request form data + * + * @return map of all form fields + */ + private Map getFieldsMap() + { + // NOTE: This class is not thread safe - it is expected to be constructed on each thread. + if (fields == null) + { + FileItemFactory factory = new DiskFileItemFactory(); + upload = new ServletFileUpload(factory); + encoding = req.getCharacterEncoding(); + upload.setHeaderEncoding(encoding); + try + { + List fileItems = upload.parseRequest(req); + fields = new HashMap(); + for (FileItem fileItem : fileItems) + { + FormField formField = new FormField(fileItem); + fields.put(fileItem.getFieldName(), formField); + } + } + catch(FileUploadException e) + { + // NOTE: assume no files can be located + fields = Collections.emptyMap(); + } + } + return fields; + } + + /** + * Helper to parse servlet request form data + * + * @return map of all form parameters + */ + private Map getParametersMap() + { + if (parameters == null) + { + Map fields = getFieldsMap(); + parameters = new HashMap(); + for (Map.Entry entry : fields.entrySet()) + { + FormField field = entry.getValue(); + if (!field.getIsFile()) + { + parameters.put(entry.getKey(), field.getValue()); + } + } + } + return parameters; + } + + /** + * Helper to parse servlet request form data + * + * @return map of all form files + */ + private Map getFilesMap() + { + if (files == null) + { + Map fields = getFieldsMap(); + files = new HashMap(); + for (Map.Entry entry : fields.entrySet()) + { + FormField field = entry.getValue(); + if (field.getIsFile()) + { + files.put(entry.getKey(), field.getContent()); + } + } + } + return files; + } + + + /** + * Form Field + * + * @author davidc + */ + public class FormField implements Serializable + { + private FileItem file; + + /** + * Construct + * + * @param file + */ + public FormField(FileItem file) + { + this.file = file; + } + + /** + * @return field name + */ + public String getName() + { + return file.getFieldName(); + } + + public String jsGet_name() + { + return getName(); + } + + /** + * @return true => field represents a file + */ + public boolean getIsFile() + { + return !file.isFormField(); + } + + public boolean jsGet_isFile() + { + return getIsFile(); + } + + /** + * @return field value (for file, attempts conversion to string) + */ + public String getValue() + { + try + { + return (file.isFormField() && encoding != null) ? file.getString(encoding) : file.getString(); + } + catch (UnsupportedEncodingException e) + { + throw new AlfrescoRuntimeException("Unable to decode form field", e); + } + } + + public String jsGet_value() + { + return getValue(); + } + + /** + * @return field as content + */ + public ScriptContent getContent() + { + try + { + return new ScriptNode.ScriptContentStream(file.getInputStream(), getMimetype(), null); + } + catch(IOException e) + { + return null; + } + } + + public ScriptContent jsGet_content() + { + return getContent(); + } + + /** + * @return mimetype + */ + public String getMimetype() + { + return file.getContentType(); + } + + public String jsGet_mimetype() + { + return getMimetype(); + } + + /** + * @return filename (only for file fields, otherwise null) + */ + public String getFilename() + { + // workaround a bug in IE where the full path is returned + return FilenameUtils.getName(file.getName()); + } + + public String jsGet_filename() + { + return getFilename(); + } + } +} diff --git a/source/java/org/alfresco/web/scripts/FormatMap.java b/source/java/org/alfresco/web/scripts/FormatMap.java new file mode 100644 index 0000000000..d1b72990c7 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/FormatMap.java @@ -0,0 +1,83 @@ +/* + * 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.Map; + +import org.springframework.beans.factory.InitializingBean; + + +/** + * A map of mimetypes indexed by format. + * + * @author davidc + */ +public class FormatMap implements InitializingBean +{ + private FormatRegistry registry; + private String agent; + private Map formats; + + + /** + * Sets the Format Registry + * + * @param registry + */ + public void setRegistry(FormatRegistry registry) + { + this.registry = registry; + } + + /** + * Sets the User Agent for which the formats apply + * + * @param agent + */ + public void setAgent(String agent) + { + this.agent = agent; + } + + /** + * Sets the formats + * + * @param formats + */ + public void setFormats(Map formats) + { + this.formats = formats; + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + public void afterPropertiesSet() throws Exception + { + // Add formats to format registry + registry.addFormats(agent, formats); + } + +} diff --git a/source/java/org/alfresco/web/scripts/FormatRegistry.java b/source/java/org/alfresco/web/scripts/FormatRegistry.java new file mode 100644 index 0000000000..a1a621afde --- /dev/null +++ b/source/java/org/alfresco/web/scripts/FormatRegistry.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; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Maintains a registry of mimetypes (indexed by format and user agent) + * + * @author davidc + */ +public class FormatRegistry +{ + // Logger + private static final Log logger = LogFactory.getLog(FormatRegistry.class); + + private Map formats; + private Map mimetypes; + private Map> agentFormats; + private Map> agentMimetypes; + + + /** + * Construct + */ + public FormatRegistry() + { + formats = new HashMap(); + mimetypes = new HashMap(); + agentFormats = new HashMap>(); + agentMimetypes = new HashMap>(); + } + + /** + * Add formats + * + * @param agent + * @param formatsToAdd + */ + public void addFormats(String agent, Map formatsToAdd) + { + // retrieve formats list for agent + Map formatsForAgent = formats; + Map mimetypesForAgent = mimetypes; + if (agent != null) + { + formatsForAgent = agentFormats.get(agent); + if (formatsForAgent == null) + { + formatsForAgent = new HashMap(); + mimetypesForAgent = new HashMap(); + agentFormats.put(agent, formatsForAgent); + agentMimetypes.put(agent, mimetypesForAgent); + } + } + + for (Map.Entry entry : formatsToAdd.entrySet()) + { + if (logger.isWarnEnabled()) + { + String mimetype = formatsForAgent.get(entry.getKey()); + if (mimetype != null) + { + logger.warn("Replacing mime type '" + mimetype + "' with '" + entry.getValue() + "' for Web Script format '" + entry.getKey() + "' (agent: " + agent + ")"); + } + } + + formatsForAgent.put(entry.getKey(), entry.getValue()); + mimetypesForAgent.put(entry.getValue(), entry.getKey()); + + if (logger.isDebugEnabled()) + logger.debug("Registered Web Script format '" + entry.getKey() + "' with mime type '" + entry.getValue() + "' (agent: " + agent + ")"); + } + } + + /** + * Gets the mimetype for the specified user agent and format + * + * @param agent + * @param format + * @return mimetype (or null, if one is not registered) + */ + public String getMimeType(String agent, String format) + { + String mimetype = null; + + if (agent != null) + { + Map formatsForAgent = agentFormats.get(agent); + if (formatsForAgent != null) + { + mimetype = formatsForAgent.get(format); + } + } + + if (mimetype == null) + { + mimetype = formats.get(format); + } + + return mimetype; + } + + /** + * Gets the format for the specified user agent and mimetype + * + * @param agent + * @param mimetype + * @return format (or null, if one is not registered) + */ + public String getFormat(String agent, String mimetype) + { + String format = null; + + if (agent != null) + { + Map mimetypesForAgent = agentMimetypes.get(agent); + if (mimetypesForAgent != null) + { + format = mimetypesForAgent.get(mimetype); + } + } + + if (format == null) + { + format = mimetypes.get(mimetype); + } + + return format; + } + +} diff --git a/source/java/org/alfresco/web/scripts/MultiScriptLoader.java b/source/java/org/alfresco/web/scripts/MultiScriptLoader.java new file mode 100644 index 0000000000..1f3ae148d9 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/MultiScriptLoader.java @@ -0,0 +1,66 @@ +/* + * 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.service.cmr.repository.ScriptLocation; + + +/** + * Composite script loader + * + * @author davidc + */ +public class MultiScriptLoader implements ScriptLoader +{ + private ScriptLoader[] loaders; + + /** + * Construct + * + * @param loaders + */ + public MultiScriptLoader(ScriptLoader[] loaders) + { + this.loaders = loaders; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.ScriptLoader#getScriptLocation(java.lang.String) + */ + public ScriptLocation getScriptLocation(String path) + { + ScriptLocation location = null; + for (ScriptLoader loader : loaders) + { + location = loader.getScriptLocation(path); + if (location != null) + { + break; + } + } + return location; + } + +} diff --git a/source/java/org/alfresco/web/scripts/Path.java b/source/java/org/alfresco/web/scripts/Path.java new file mode 100644 index 0000000000..50f9d56628 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/Path.java @@ -0,0 +1,149 @@ +/* + * 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.Map; +import java.util.TreeMap; + + +/** + * Basic implementation of a Web Script Path + * + * Used for package & url trees. + * + * @author davidc + */ +public class Path implements WebScriptPath +{ + private String path; + private Path parent = null; + private Map children = new TreeMap(); + private Map scripts = new TreeMap(); + + + /** + * Helper to concatenate paths + * + * @param path1 + * @param path2 + * @return concatenated path + */ + public static String concatPath(String path1, String path2) + { + return path1.equals("/") ? path1 + path2 : path1 + "/" + path2; + } + + + /** + * Construct + * + * @param path + */ + public Path(String path) + { + this.path = path; + } + + /** + * Create a Child Path + * + * @param path child path name + * @return child path + */ + public Path createChildPath(String path) + { + Path child = new Path(concatPath(this.path, path)); + child.parent = this; + children.put(child.path, child); + return child; + } + + /** + * Associate Web Script with Path + * + * @param script + */ + public void addScript(WebScript script) + { + scripts.put(script.getDescription().getId(), script); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptPath#getChildren() + */ + public WebScriptPath[] getChildren() + { + WebScriptPath[] childrenArray = new WebScriptPath[children.size()]; + return children.values().toArray(childrenArray); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptPath#getScripts() + */ + public WebScript[] getScripts() + { + WebScript[] scriptsArray = new WebScript[scripts.size()]; + return scripts.values().toArray(scriptsArray); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptPath#getName() + */ + public String getName() + { + String name = ""; + int i = path.lastIndexOf("/"); + if (i != -1 && i != (path.length() -1)) + { + name = path.substring(i + 1); + } + return name; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptPath#getParent() + */ + public WebScriptPath getParent() + { + return parent; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptPath#getPath() + */ + public String getPath() + { + return path; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() + { + return path; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepoStore.java b/source/java/org/alfresco/web/scripts/RepoStore.java similarity index 93% rename from source/java/org/alfresco/repo/web/scripts/RepoStore.java rename to source/java/org/alfresco/web/scripts/RepoStore.java index 7520f0f583..2d17d815e9 100644 --- a/source/java/org/alfresco/repo/web/scripts/RepoStore.java +++ b/source/java/org/alfresco/web/scripts/RepoStore.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts; +package org.alfresco.web.scripts; import java.io.IOException; import java.io.InputStream; @@ -46,17 +46,13 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.ScriptLocation; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.AbstractLifecycleBean; -import org.alfresco.web.scripts.ScriptContent; -import org.alfresco.web.scripts.ScriptLoader; -import org.alfresco.web.scripts.Store; -import org.alfresco.web.scripts.WebScript; -import org.alfresco.web.scripts.WebScriptException; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -71,7 +67,7 @@ import freemarker.cache.TemplateLoader; * * @author davidc */ -public class RepoStore implements Store, ApplicationContextAware, ApplicationListener +public class RepoStore implements WebScriptStore, ApplicationContextAware, ApplicationListener { private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); protected boolean mustExist = false; @@ -626,21 +622,21 @@ public class RepoStore implements Store, ApplicationContextAware, ApplicationLis /* (non-Javadoc) * @see org.alfresco.web.scripts.ScriptLoader#getScriptLocation(java.lang.String) */ - public ScriptContent getScript(final String path) + public ScriptLocation getScriptLocation(final String path) { - return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() + return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { - public ScriptContent doWork() throws Exception + public ScriptLocation doWork() throws Exception { - return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() { - public ScriptContent execute() throws Exception + public ScriptLocation execute() throws Exception { - ScriptContent location = null; + ScriptLocation location = null; NodeRef nodeRef = findNodeRef(path); if (nodeRef != null) { - location = new RepoScriptContent(path, nodeRef); + location = new RepoScriptLocation(path, nodeRef); } return location; } @@ -655,7 +651,7 @@ public class RepoStore implements Store, ApplicationContextAware, ApplicationLis * * @author davidc */ - private class RepoScriptContent implements ScriptContent + private class RepoScriptLocation implements ScriptLocation { protected String path; protected NodeRef nodeRef; @@ -665,7 +661,7 @@ public class RepoStore implements Store, ApplicationContextAware, ApplicationLis * * @param location */ - public RepoScriptContent(String path, NodeRef nodeRef) + public RepoScriptLocation(String path, NodeRef nodeRef) { this.path = path; this.nodeRef = nodeRef; diff --git a/source/java/org/alfresco/web/scripts/ScriptLoader.java b/source/java/org/alfresco/web/scripts/ScriptLoader.java new file mode 100644 index 0000000000..e3d674f72a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ScriptLoader.java @@ -0,0 +1,46 @@ +/* + * 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.service.cmr.repository.ScriptLocation; + + +/** + * Locate a script + * + * @author davidc + */ +public interface ScriptLoader +{ + + /** + * Gets the script location for the script at the specified path + * + * @param path path within api store + * @return script location (or null, if script does not exist at path) + */ + ScriptLocation getScriptLocation(String path); + +} diff --git a/source/java/org/alfresco/web/scripts/ScriptProcessor.java b/source/java/org/alfresco/web/scripts/ScriptProcessor.java new file mode 100644 index 0000000000..be9981ca22 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ScriptProcessor.java @@ -0,0 +1,119 @@ +/* + * 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.Map; + +import org.alfresco.service.cmr.repository.ScriptException; +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.alfresco.service.cmr.repository.ScriptService; + + +/** + * Script Processor for use in Web Script + * + * @author davidc + */ +public class ScriptProcessor +{ + // dependencies + private ScriptService scriptService; + + // script loader + private ScriptLoader scriptLoader; + + /** + * Sets the script service + * + * @param scriptService + */ + public void setScriptService(ScriptService scriptService) + { + this.scriptService = scriptService; + } + + /** + * Sets the script loader + * + * @param scriptLoader + */ + public void setScriptLoader(ScriptLoader scriptLoader) + { + this.scriptLoader = scriptLoader; + } + + /** + * Find a script at the specified path (within registered Web Script stores) + * + * @param path script path + * @return script location (or null, if not found) + */ + public ScriptLocation findScript(String path) + { + return scriptLoader.getScriptLocation(path); + } + + /** + * Execute script + * + * @param path script path + * @param model model + * @return script result + * @throws ScriptException + */ + public Object executeScript(String path, Map model) + throws ScriptException + { + // locate script within web script stores + ScriptLocation scriptLocation = findScript(path); + if (scriptLocation == null) + { + throw new WebScriptException("Unable to locate script " + path); + } + // execute script + return executeScript(scriptLocation, model); + } + + /** + * Execute script + * + * @param location script location + * @param model model + * @return script result + */ + public Object executeScript(ScriptLocation location, Map model) + { + return scriptService.executeScript("javascript", location, model); + } + + /** + * Reset script cache + */ + public void resetCache() + { + // NOOP + } + +} 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..25e27bf9bb --- /dev/null +++ b/source/java/org/alfresco/web/scripts/ScriptUrlMethod.java @@ -0,0 +1,114 @@ +/* + * 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 org.alfresco.web.scripts.WebScriptDescription.FormatStyle; + +import freemarker.template.TemplateBooleanModel; +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() != 0) + { + Object arg0 = args.get(0); + boolean prefixServiceUrl = true; + if (args.size() == 2 && args.get(1) instanceof TemplateBooleanModel) + { + prefixServiceUrl = ((TemplateBooleanModel)args.get(1)).getAsBoolean(); + } + + if (arg0 instanceof TemplateScalarModel) + { + String arg = ((TemplateScalarModel)arg0).getAsString(); + + StringBuffer buf = new StringBuffer(128); + buf.append(prefixServiceUrl ? req.getServicePath() : ""); + buf.append(arg); + if (arg.length() != 0) + { + if (arg.indexOf('?') == -1) + { + buf.append('?'); + } + else + { + buf.append('&'); + } + } + else + { + buf.append('?'); + } + buf.append("guest=" + (req.isGuest() ? "true" : "")); + if (req.getFormatStyle() == FormatStyle.argument) + { + buf.append("&format="); + buf.append(req.getFormat()); + } + + result = res.encodeScriptUrl(buf.toString()); + } + } + + return result; + } +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java b/source/java/org/alfresco/web/scripts/ServerModel.java similarity index 57% rename from source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java rename to source/java/org/alfresco/web/scripts/ServerModel.java index 4cd4ce28a6..c7ce52b2e6 100644 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryServerModel.java +++ b/source/java/org/alfresco/web/scripts/ServerModel.java @@ -1,122 +1,169 @@ -/* - * 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.repo.web.scripts; - -import org.alfresco.service.descriptor.Descriptor; -import org.alfresco.web.scripts.ServerModel; - - -/** - * Script / Template Model representing Repository Server meta-data - * - * @author davidc - */ -public class RepositoryServerModel implements ServerModel -{ - private Descriptor serverDescriptor; - - /** - * Construct - * - * @param serverDescriptor - */ - /*package*/ RepositoryServerModel(Descriptor serverDescriptor) - { - this.serverDescriptor = serverDescriptor; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getContainerName() - */ - public String getContainerName() - { - return "Repository"; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersionMajor() - */ - public String getVersionMajor() - { - return serverDescriptor.getVersionMajor(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersionMinor() - */ - public String getVersionMinor() - { - return serverDescriptor.getVersionMinor(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersionRevision() - */ - public String getVersionRevision() - { - return serverDescriptor.getVersionRevision(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersionLabel() - */ - public String getVersionLabel() - { - return serverDescriptor.getVersionLabel(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersionBuild() - */ - public String getVersionBuild() - { - return serverDescriptor.getVersionBuild(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getVersion() - */ - public String getVersion() - { - return serverDescriptor.getVersion(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getEdition() - */ - public String getEdition() - { - return serverDescriptor.getEdition(); - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.ServerModel#getSchema() - */ - public int getSchema() - { - return serverDescriptor.getSchema(); - } - -} +/* + * 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.service.descriptor.Descriptor; + + +/** + * Script / Template Model representing Repository Server meta-data + * + * @author davidc + */ +public class ServerModel +{ + private Descriptor serverDescriptor; + + /** + * Construct + * + * @param serverDescriptor + */ + /*package*/ ServerModel(Descriptor serverDescriptor) + { + this.serverDescriptor = serverDescriptor; + } + + /** + * Gets the major version number, e.g. 1.2.3 + * + * @return major version number + */ + public String getVersionMajor() + { + return serverDescriptor.getVersionMajor(); + } + + public String jsGet_versionMajor() + { + return getVersionMajor(); + } + + /** + * Gets the minor version number, e.g. 1.2.3 + * + * @return minor version number + */ + public String getVersionMinor() + { + return serverDescriptor.getVersionMinor(); + } + + public String jsGet_versionMinor() + { + return getVersionMinor(); + } + + /** + * Gets the version revision number, e.g. 1.2.3 + * + * @return revision number + */ + public String getVersionRevision() + { + return serverDescriptor.getVersionRevision(); + } + + public String jsGet_versionRevision() + { + return getVersionRevision(); + } + + /** + * Gets the version label + * + * @return the version label + */ + public String getVersionLabel() + { + return serverDescriptor.getVersionLabel(); + } + + public String jsGet_versionLabel() + { + return getVersionLabel(); + } + + /** + * Gets the build number + * + * @return the build number i.e. build-1 + */ + public String getVersionBuild() + { + return serverDescriptor.getVersionBuild(); + } + + public String jsGet_versionBuild() + { + return getVersionBuild(); + } + + /** + * Gets the full version number + * + * @return full version number as major.minor.revision (label) + */ + public String getVersion() + { + return serverDescriptor.getVersion(); + } + + public String jsGet_version() + { + return getVersion(); + } + + /** + * Gets the edition + * + * @return the edition + */ + public String getEdition() + { + return serverDescriptor.getEdition(); + } + + public String jsGet_edition() + { + return getEdition(); + } + + /** + * Gets the schema number + * + * @return a positive integer + */ + public int getSchema() + { + return serverDescriptor.getSchema(); + } + + public int jsGet_schema() + { + return getSchema(); + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java b/source/java/org/alfresco/web/scripts/TemplateProcessor.java similarity index 68% rename from source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java rename to source/java/org/alfresco/web/scripts/TemplateProcessor.java index d30f1e7b3a..3eca3d8685 100644 --- a/source/java/org/alfresco/repo/web/scripts/RepositoryTemplateProcessor.java +++ b/source/java/org/alfresco/web/scripts/TemplateProcessor.java @@ -1,205 +1,218 @@ -package org.alfresco.repo.web.scripts; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.alfresco.repo.template.FreeMarkerProcessor; -import org.alfresco.repo.template.QNameAwareObjectWrapper; -import org.alfresco.service.cmr.repository.ProcessorExtension; -import org.alfresco.util.AbstractLifecycleBean; -import org.alfresco.web.scripts.SearchPath; -import org.alfresco.web.scripts.Store; -import org.alfresco.web.scripts.TemplateProcessor; -import org.alfresco.web.scripts.WebScriptException; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; - -import freemarker.cache.MruCacheStorage; -import freemarker.cache.MultiTemplateLoader; -import freemarker.cache.TemplateLoader; -import freemarker.template.Configuration; -import freemarker.template.Template; -import freemarker.template.TemplateExceptionHandler; - - -public class RepositoryTemplateProcessor extends FreeMarkerProcessor - implements TemplateProcessor, ApplicationContextAware, ApplicationListener -{ - private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); - protected SearchPath searchPath; - protected String defaultEncoding; - protected Configuration templateConfig; - protected FreeMarkerProcessor freeMarkerProcessor; - - - /* (non-Javadoc) - * @see org.alfresco.repo.template.FreeMarkerProcessor#setDefaultEncoding(java.lang.String) - */ - public void setDefaultEncoding(String defaultEncoding) - { - this.defaultEncoding = defaultEncoding; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.TemplateProcessor#getDefaultEncoding() - */ - public String getDefaultEncoding() - { - return this.defaultEncoding; - } - - public void setSearchPath(SearchPath searchPath) - { - this.searchPath = searchPath; - } - - /** - * Set the freemarker processor - * - * @param freeMarkerProcessor the free marker processor - */ - public void setFreeMarkerProcessor(FreeMarkerProcessor freeMarkerProcessor) - { - this.freeMarkerProcessor = freeMarkerProcessor; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.template.FreeMarkerProcessor#getConfig() - */ - @Override - protected Configuration getConfig() - { - return templateConfig; - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.TemplateProcessor#reset() - */ - public void reset() - { - if (templateConfig != null) - { - templateConfig.clearTemplateCache(); - } - } - - /* (non-Javadoc) - * @see org.alfresco.web.scripts.TemplateProcessor#hasTemplate(java.lang.String) - */ - public boolean hasTemplate(String templatePath) - { - boolean hasTemplate = false; - try - { - Template template = templateConfig.getTemplate(templatePath); - hasTemplate = (template != null); - } - catch(FileNotFoundException e) - { - // NOTE: return false as template is not found - } - catch(IOException e) - { - throw new WebScriptException("Failed to retrieve template " + templatePath, e); - } - return hasTemplate; - } - - /** - * Initialise FreeMarker Configuration - */ - protected void initConfig() - { - Configuration config = new Configuration(); - - // setup template cache - config.setCacheStorage(new MruCacheStorage(20, 100)); - config.setTemplateUpdateDelay(0); - - // setup template loaders - List loaders = new ArrayList(); - for (Store apiStore : searchPath.getStores()) - { - TemplateLoader loader = apiStore.getTemplateLoader(); - if (loader == null) - { - throw new WebScriptException("Unable to retrieve template loader for Web Script store " + apiStore.getBasePath()); - } - loaders.add(loader); - } - MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()])); - config.setTemplateLoader(loader); - - // use our custom object wrapper that can deal with QNameMap objects directly - config.setObjectWrapper(new QNameAwareObjectWrapper()); - - // rethrow any exception so we can deal with them - config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); - - // turn off locale sensitive lookup - to save numerous wasted calls to nodeservice.exists() - config.setLocalizedLookup(false); - - // set template encoding - if (defaultEncoding != null) - { - config.setDefaultEncoding(defaultEncoding); - } - - // set output encoding - config.setOutputEncoding("UTF-8"); - - templateConfig = config; - } - - /** - * Tempory fix to initialise this template processor with the freeMarker extensions expected by - * the templates. - */ - private void initProcessorExtensions() - { - for (ProcessorExtension processorExtension : this.freeMarkerProcessor.getProcessorExtensions()) - { - this.registerProcessorExtension(processorExtension); - } - } - - /* (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - lifecycle.setApplicationContext(applicationContext); - } - - /* (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) - { - lifecycle.onApplicationEvent(event); - } - - /** - * Hooks into Spring Application Lifecycle - */ - private class ProcessorLifecycle extends AbstractLifecycleBean - { - @Override - protected void onBootstrap(ApplicationEvent event) - { - initConfig(); - initProcessorExtensions(); - } - - @Override - protected void onShutdown(ApplicationEvent event) - { - } - } - -} +/* + * 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.FileNotFoundException; +import java.io.IOException; + +import org.alfresco.repo.template.FreeMarkerProcessor; +import org.alfresco.repo.template.QNameAwareObjectWrapper; +import org.alfresco.service.cmr.repository.ProcessorExtension; +import org.alfresco.util.AbstractLifecycleBean; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +import freemarker.cache.MruCacheStorage; +import freemarker.cache.TemplateLoader; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateExceptionHandler; + + +/** + * FreeMarker Processor for use in Web Scripts + * + * Adds the ability to: + * - specify template loaders + * - caching of templates + * + * @author davidc + */ +public class TemplateProcessor extends FreeMarkerProcessor implements ApplicationContextAware, ApplicationListener +{ + private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); + protected TemplateLoader templateLoader = null; + protected String defaultEncoding; + protected Configuration templateConfig; + protected FreeMarkerProcessor freeMarkerProcessor; + + + /* (non-Javadoc) + * @see org.alfresco.repo.template.FreeMarkerProcessor#setDefaultEncoding(java.lang.String) + */ + public void setDefaultEncoding(String defaultEncoding) + { + this.defaultEncoding = defaultEncoding; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.template.FreeMarkerProcessor#getConfig() + */ + @Override + protected Configuration getConfig() + { + return templateConfig; + } + + /** + * Sets the Template Loader + * + * @param templateLoader template loader + */ + public void setTemplateLoader(TemplateLoader templateLoader) + { + this.templateLoader = templateLoader; + } + + /** + * Set the freemarker processor + * + * @param freeMarkerProcessor the free marker processor + */ + public void setFreeMarkerProcessor(FreeMarkerProcessor freeMarkerProcessor) + { + this.freeMarkerProcessor = freeMarkerProcessor; + } + + /** + * Reset template cache + */ + public void resetCache() + { + if (templateConfig != null) + { + templateConfig.clearTemplateCache(); + } + } + + /** + * Determines if a template exists + * + * @param template + * @return true => exists + */ + public boolean hasTemplate(String templatePath) + { + boolean hasTemplate = false; + try + { + Template template = templateConfig.getTemplate(templatePath); + hasTemplate = (template != null); + } + catch(FileNotFoundException e) + { + // NOTE: return false as template is not found + } + catch(IOException e) + { + throw new WebScriptException("Failed to retrieve template " + templatePath, e); + } + return hasTemplate; + } + + /** + * Initialise FreeMarker Configuration + */ + protected void initConfig() + { + Configuration config = new Configuration(); + + // setup template cache + config.setCacheStorage(new MruCacheStorage(20, 100)); + + // setup template loaders + config.setTemplateLoader(templateLoader); + + // use our custom object wrapper that can deal with QNameMap objects directly + config.setObjectWrapper(new QNameAwareObjectWrapper()); + + // rethrow any exception so we can deal with them + config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + + // turn off locale sensitive lookup - to save numerous wasted calls to nodeservice.exists() + config.setLocalizedLookup(false); + + // set template encoding + if (defaultEncoding != null) + { + config.setDefaultEncoding(defaultEncoding); + } + + // set output encoding + config.setOutputEncoding("UTF-8"); + + templateConfig = config; + } + + /** + * Tempory fix to initialise this template processor with the freeMarker extensions expected by + * the templates. + */ + private void initProcessorExtensions() + { + for (ProcessorExtension processorExtension : this.freeMarkerProcessor.getProcessorExtensions()) + { + this.registerProcessorExtension(processorExtension); + } + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + lifecycle.setApplicationContext(applicationContext); + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + public void onApplicationEvent(ApplicationEvent event) + { + lifecycle.onApplicationEvent(event); + } + + /** + * Hooks into Spring Application Lifecycle + */ + private class ProcessorLifecycle extends AbstractLifecycleBean + { + @Override + protected void onBootstrap(ApplicationEvent event) + { + initConfig(); + initProcessorExtensions(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/TestWebScriptServer.java b/source/java/org/alfresco/web/scripts/TestWebScriptServer.java new file mode 100644 index 0000000000..10e975f255 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/TestWebScriptServer.java @@ -0,0 +1,536 @@ +/* + * 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.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.config.Config; +import org.alfresco.config.ConfigService; +import org.alfresco.repo.security.authentication.AuthenticationException; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.web.config.ServerConfigElement; +import org.springframework.context.ApplicationContext; +import org.springframework.context.MessageSource; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + + +/** + * Stand-alone Web Script Test Server + * + * @author davidc + */ +public class TestWebScriptServer +{ + // dependencies + protected AuthenticationService authenticationService; + protected DeclarativeWebScriptRegistry registry; + protected ConfigService configService; + protected ServiceRegistry serviceRegistry; + protected RetryingTransactionHelper retryingTransactionHelper; + + /** Server Configuration */ + private ServerConfigElement serverConfig; + + /** The reader for interaction. */ + private BufferedReader fIn; + + /** Last command issued */ + private String lastCommand = null; + + /** Current user */ + private String username = "admin"; + + /** Current headers */ + private Map headers = new HashMap(); + + /** I18N Messages */ + private MessageSource m_messages; + + + /** + * Sets helper that provides transaction callbacks + */ + public void setTransactionHelper(RetryingTransactionHelper retryingTransactionHelper) + { + this.retryingTransactionHelper = retryingTransactionHelper; + } + + /** + * Sets the Web Script Registry + * + * @param registry + */ + public void setRegistry(DeclarativeWebScriptRegistry registry) + { + this.registry = registry; + } + + /** + * Sets the Service Registry + * + * @param registry + */ + public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /** + * Sets the Config Service + * + * @param configService + */ + public void setConfigService(ConfigService configService) + { + this.configService = configService; + } + + /** + * @param authenticationService + */ + public void setAuthenticationService(AuthenticationService authenticationService) + { + this.authenticationService = authenticationService; + } + + /** + * Sets the Messages resource bundle + * + * @param messages + * @throws IOException + */ + public void setMessages(MessageSource messages) + throws IOException + { + this.m_messages = messages; + } + + + /** + * Initialise the Test Web Script Server + * + * @throws Exception + */ + public void init() + { + Config config = configService.getConfig("Server"); + serverConfig = (ServerConfigElement)config.getConfigElement(ServerConfigElement.CONFIG_ELEMENT_ID); + } + + /** + * Main entry point. + */ + public static void main(String[] args) + { + try + { + TestWebScriptServer testServer = getTestServer(); + testServer.rep(); + } + catch(Throwable e) + { + StringWriter strWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(strWriter); + e.printStackTrace(printWriter); + System.out.println(strWriter.toString()); + } + finally + { + System.exit(0); + } + } + + /** + * Retrieve an instance of the TestWebScriptServer + * + * @return Test Server + */ + public static TestWebScriptServer getTestServer() + { + String[] CONFIG_LOCATIONS = new String[] + { + "classpath:alfresco/application-context.xml", + "classpath:alfresco/web-scripts-application-context.xml", + "classpath:alfresco/web-client-application-context.xml", + "classpath:alfresco/web-scripts-application-context-test.xml" + }; + ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); + TestWebScriptServer testServer = (TestWebScriptServer)context.getBean("webscripts.test"); + testServer.init(); + return testServer; + } + + /** + * Submit a Web Script Request + * + * @param method http method + * @param uri web script uri (relative to /alfresco/service) + * @return response + * @throws IOException + */ + public MockHttpServletResponse submitRequest(String method, String uri) + throws IOException + { + MockHttpServletRequest req = createRequest(method, uri); + MockHttpServletResponse res = new MockHttpServletResponse(); + + WebScriptRuntime runtime = new WebScriptServletRuntime(registry, serviceRegistry, null, req, res, serverConfig); + runtime.executeScript(); + + return res; + } + + /** + * Submit a Web Script Request + * + * @param method http method + * @param uri web script uri (relative to /alfresco/service) + * @param headers headers + * @return response + * @throws IOException + */ + public MockHttpServletResponse submitRequest(String method, String uri, Map headers) + throws IOException + { + MockHttpServletRequest req = createRequest(method, uri); + for (Map.Entry header: headers.entrySet()) + { + req.addHeader(header.getKey(), header.getValue()); + } + MockHttpServletResponse res = new MockHttpServletResponse(); + + WebScriptRuntime runtime = new WebScriptServletRuntime(registry, serviceRegistry, null, req, res, serverConfig); + runtime.executeScript(); + + return res; + } + + /** + * A Read-Eval-Print loop. + */ + /*package*/ void rep() + { + // accept commands + fIn = new BufferedReader(new InputStreamReader(System.in)); + while (true) + { + System.out.print("ok> "); + try + { + // get command + final String line = fIn.readLine(); + if (line.equals("exit") || line.equals("quit")) + { + return; + } + + // execute command in context of currently selected user + long startms = System.currentTimeMillis(); + System.out.print(interpretCommand(line)); + System.out.println("" + (System.currentTimeMillis() - startms) + "ms"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + System.out.println(""); + } + } + } + + /** + * Interpret a single command using the BufferedReader passed in for any data needed. + * + * @param line The unparsed command + * @return The textual output of the command. + */ + private String interpretCommand(final String line) + throws IOException + { + try + { + if (username.startsWith("TICKET_")) + { + try + { + retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + authenticationService.validate(username); + return null; + } + }); + return executeCommand(line); + } + finally + { + authenticationService.clearCurrentSecurityContext(); + } + } + } + catch(AuthenticationException e) + { + executeCommand("user admin"); + } + + // execute command in context of currently selected user + return AuthenticationUtil.runAs(new RunAsWork() + { + @SuppressWarnings("synthetic-access") + public String doWork() throws Exception + { + return executeCommand(line); + } + }, username); + } + + /** + * Execute a single command using the BufferedReader passed in for any data needed. + * + * TODO: Use decent parser! + * + * @param line The unparsed command + * @return The textual output of the command. + */ + private String executeCommand(String line) + throws IOException + { + String[] command = line.split(" "); + if (command.length == 0) + { + command = new String[1]; + command[0] = line; + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(bout); + + // repeat last command? + if (command[0].equals("r")) + { + if (lastCommand == null) + { + return "No command entered yet."; + } + return "repeating command " + lastCommand + "\n\n" + interpretCommand(lastCommand); + } + + // remember last command + lastCommand = line; + + // execute command + if (command[0].equals("help")) + { + String helpFile = m_messages.getMessage("testserver.help", null, null); + ClassPathResource helpResource = new ClassPathResource(helpFile); + byte[] helpBytes = new byte[500]; + InputStream helpStream = helpResource.getInputStream(); + try + { + int read = helpStream.read(helpBytes); + while (read != -1) + { + bout.write(helpBytes, 0, read); + read = helpStream.read(helpBytes); + } + } + finally + { + helpStream.close(); + } + } + + else if (command[0].equals("user")) + { + if (command.length == 2) + { + username = command[1]; + } + out.println("using user " + username); + } + + else if (command[0].equals("get") || + command[0].equals("put") || + command[0].equals("post") || + command[0].equals("delete")) + { + String uri = (command.length > 1) ? command[1] : null; + MockHttpServletResponse res = submitRequest(command[0], uri, headers); + bout.write(("Response status: " + res.getStatus()).getBytes()); + out.println(); + bout.write(res.getContentAsByteArray()); + out.println(); + } + + else if (command[0].equals("tunnel")) + { + if (command.length < 4) + { + return "Syntax Error.\n"; + } + + if (command[1].equals("param")) + { + String uri = command[3]; + if (uri.indexOf('?') == -1) + { + uri += "?alf:method=" + command[2]; + } + else + { + uri += "&alf:method=" + command[2]; + } + MockHttpServletResponse res = submitRequest("post", uri, headers); + bout.write(res.getContentAsByteArray()); + out.println(); + } + + else if (command[1].equals("header")) + { + Map tunnelheaders = new HashMap(); + tunnelheaders.putAll(headers); + tunnelheaders.put("X-HTTP-Method-Override", command[2]); + MockHttpServletResponse res = submitRequest("post", command[3], tunnelheaders); + bout.write(res.getContentAsByteArray()); + out.println(); + } + + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("header")) + { + if (command.length == 1) + { + for (Map.Entry entry : headers.entrySet()) + { + out.println(entry.getKey() + " = " + entry.getValue()); + } + } + else if (command.length == 2) + { + String[] param = command[1].split("="); + if (param.length == 0) + { + return "Syntax Error.\n"; + } + if (param.length == 1) + { + headers.remove(param[0]); + out.println("deleted header " + param[0]); + } + else if (param.length == 2) + { + headers.put(param[0], param[1]); + out.println("set header " + param[0] + " = " + headers.get(param[0])); + } + else + { + return "Syntax Error.\n"; + } + } + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("reset")) + { + registry.reset(); + out.println("Registry reset."); + } + + else + { + return "Syntax Error.\n"; + } + + out.flush(); + String retVal = new String(bout.toByteArray()); + out.close(); + return retVal; + } + + /** + * Create a Mock HTTP Servlet Request + * + * @param method + * @param uri + * @return mock http servlet request + * @throws UnsupportedEncodingException + */ + private MockHttpServletRequest createRequest(String method, String uri) + throws UnsupportedEncodingException + { + MockHttpServletRequest req = new MockHttpServletRequest(method, uri); + + req.setContextPath("/alfresco"); + req.setServletPath("/service"); + + if (uri != null) + { + int iArgIndex = uri.indexOf('?'); + if (iArgIndex != -1 && iArgIndex != uri.length() -1) + { + String uriArgs = uri.substring(iArgIndex +1); + String[] args = uriArgs.split("&"); + for (String arg : args) + { + String[] parts = arg.split("="); + req.addParameter(parts[0], (parts.length == 2) ? URLDecoder.decode(parts[1], "UTF-8") : null); + } + req.setQueryString(URLDecoder.decode(uriArgs, "UTF-8")); + } + String requestURI = "/alfresco/service" + (iArgIndex == -1 ? uri : uri.substring(0, iArgIndex)); + req.setRequestURI(URLDecoder.decode(requestURI, "UTF-8")); + } + + return req; + } + +} diff --git a/source/java/org/alfresco/web/scripts/URLModel.java b/source/java/org/alfresco/web/scripts/URLModel.java new file mode 100644 index 0000000000..00729efc73 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/URLModel.java @@ -0,0 +1,174 @@ +/* + * 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; + + +/** + * Script / Template Model representing Web Script URLs + * + * @author davidc + */ +public class URLModel +{ + private WebScriptRequest req; + + /** + * Construct + * + * @param req + * @param res + */ + URLModel(WebScriptRequest req) + { + this.req = req; + } + + /** + * Gets the Context Path + * + * e.g. /alfresco + * + * @return context path + */ + public String getContext() + { + return req.getContextPath(); + } + + public String jsGet_context() + { + return getContext(); + } + + /** + * Gets the Service Context Path + * + * e.g. /alfresco/service + * + * @return service context path + */ + public String getServiceContext() + { + return req.getServiceContextPath(); + } + + public String jsGet_serviceContext() + { + return getServiceContext(); + } + + /** + * Gets the Service Path + * + * e.g. /alfresco/service/search/keyword + * + * @return service path + */ + public String getService() + { + return req.getServicePath(); + } + + public String jsGet_service() + { + return getService(); + } + + /** + * Gets the full path + * + * e.g. /alfresco/service/search/keyword?q=term + * + * @return service path + */ + public String getFull() + { + return req.getURL(); + } + + public String jsGet_full() + { + return getFull(); + } + + /** + * Gets the URL arguments (query string) + * + * @return args (query string) + */ + public String getArgs() + { + String args = req.getQueryString(); + return (args == null) ? "" : args; + } + + public String jsGet_args() + { + return getArgs(); + } + + /** + * Gets the matching service path + * + * e.g. + * a) service registered path = /search/engine + * b) request path = /search/engine/external + * + * => /search/engine + * + * @return matching path + */ + public String getMatch() + { + return req.getServiceMatch().getPath(); + } + + public String jsGet_match() + { + return getMatch(); + } + + /** + * Gets the Service Extension Path + * + * e.g. + * a) service registered path = /search/engine + * b) request path = /search/engine/external + * + * => /external + * + * @return extension path + */ + public String getExtension() + { + return req.getExtensionPath(); + } + + public String jsGet_extension() + { + return getExtension(); + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.java new file mode 100644 index 0000000000..2f3d463cd1 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebClientAuthenticator.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 java.io.IOException; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +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.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.context.ServletContextAware; + +/** + * Alfresco Web Client Authentication Interceptor + * + * @author davidc + */ +public class WebClientAuthenticator implements WebScriptServletAuthenticator, ServletContextAware +{ + // Logger + private static final Log logger = LogFactory.getLog(WebClientAuthenticator.class); + + // dependencies + private ServletContext context; + + + /* (non-Javadoc) + * @see org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet.ServletContext) + */ + public void setServletContext(ServletContext context) + { + this.context = context; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest preq, WebScriptServletResponse pres) + { + AuthenticationStatus status = null; + + try + { + // + // validate credentials + // + HttpServletRequest req = preq.getHttpServletRequest(); + HttpServletResponse res = pres.getHttpServletResponse(); + String ticket = req.getParameter("ticket"); + + if (logger.isDebugEnabled()) + { + 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, req, res, ticket); + } + else + { + if (isGuest && RequiredAuthentication.guest == required) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + + status = AuthenticationHelper.authenticate(context, req, res, true); + } + else + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating session"); + + status = AuthenticationHelper.authenticate(context, req, res, false, false); + } + } + + // + // if not authorized, redirect to login page + // + 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(req, res, context); + } + } + catch(IOException e) + { + throw new WebScriptException("Failed to authenticate", e); + } + + return !(status == null || status == AuthenticationStatus.Failure); + } +} diff --git a/source/java/org/alfresco/web/scripts/WebScript.java b/source/java/org/alfresco/web/scripts/WebScript.java new file mode 100644 index 0000000000..70a9cfc58e --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScript.java @@ -0,0 +1,53 @@ +/* + * 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; + +/** + * Web Script + * + * @author davidc + */ +public interface WebScript +{ + /** + * Gets the Service Description + * + * @return service description + */ + public WebScriptDescription getDescription(); + + /** + * Execute service + * + * @param req + * @param res + * @throws IOException + */ + public void execute(WebScriptRequest req, WebScriptResponse res) + throws IOException; + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptCache.java b/source/java/org/alfresco/web/scripts/WebScriptCache.java new file mode 100644 index 0000000000..506e063e22 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptCache.java @@ -0,0 +1,162 @@ +/* + * 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.Date; + + +/** + * Web Script Cache + * + * Records the desired cache requirements for the Web Script + * + * @author davidc + */ +public class WebScriptCache implements WebScriptDescription.RequiredCache +{ + private boolean neverCache = true; + private boolean isPublic = false; + private boolean mustRevalidate = true; + private Date lastModified = null; + private String eTag = null; + private Long maxAge = null; + + + /** + * Construct + */ + public WebScriptCache() + { + } + + /** + * Construct + * + * @param requiredCache + */ + public WebScriptCache(WebScriptDescription.RequiredCache requiredCache) + { + neverCache = requiredCache.getNeverCache(); + isPublic = requiredCache.getIsPublic(); + mustRevalidate = requiredCache.getMustRevalidate(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription.RequiredCache#getNeverCache() + */ + public boolean getNeverCache() + { + return neverCache; + } + + /** + * @param neverCache + */ + public void setNeverCache(boolean neverCache) + { + this.neverCache = neverCache; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription.RequiredCache#getIsPublic() + */ + public boolean getIsPublic() + { + return isPublic; + } + + /** + * @param isPublic + */ + public void setIsPublic(boolean isPublic) + { + this.isPublic = isPublic; + } + + /** + * @return last modified + */ + public Date getLastModified() + { + return lastModified; + } + + /** + * @param lastModified + */ + public void setLastModified(Date lastModified) + { + this.lastModified = lastModified; + } + + /** + * @return ETag + */ + public String getETag() + { + return eTag; + } + + /** + * @param tag ETag + */ + public void setETag(String tag) + { + eTag = tag; + } + + /** + * @return Max Age (seconds) + */ + public Long getMaxAge() + { + return maxAge; + } + + /** + * @param maxAge Max Age (seconds) + */ + public void setMaxAge(Long maxAge) + { + this.maxAge = maxAge; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription.RequiredCache#getMustRevalidate() + */ + public boolean getMustRevalidate() + { + return mustRevalidate; + } + + /** + * @param mustRevalidate + */ + public void setMustRevalidate(boolean mustRevalidate) + { + this.mustRevalidate = mustRevalidate; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/Repository.java b/source/java/org/alfresco/web/scripts/WebScriptContext.java similarity index 65% rename from source/java/org/alfresco/repo/web/scripts/Repository.java rename to source/java/org/alfresco/web/scripts/WebScriptContext.java index b85e7f377d..e6221297b8 100644 --- a/source/java/org/alfresco/repo/web/scripts/Repository.java +++ b/source/java/org/alfresco/web/scripts/WebScriptContext.java @@ -22,20 +22,14 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts; +package org.alfresco.web.scripts; -import java.util.Arrays; import java.util.List; -import javax.servlet.http.HttpServletResponse; - import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; -import org.alfresco.service.cmr.model.FileNotFoundException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -43,7 +37,6 @@ import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.AbstractLifecycleBean; -import org.alfresco.web.scripts.WebScriptException; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -56,7 +49,7 @@ import org.springframework.context.ApplicationListener; * * @author davidc */ -public class Repository implements ApplicationContextAware, ApplicationListener +public class WebScriptContext implements ApplicationContextAware, ApplicationListener { private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); @@ -65,7 +58,6 @@ public class Repository implements ApplicationContextAware, ApplicationListener private NamespaceService namespaceService; private SearchService searchService; private NodeService nodeService; - private FileFolderService fileFolderService; private PersonService personService; // company home @@ -131,17 +123,7 @@ public class Repository implements ApplicationContextAware, ApplicationListener { this.nodeService = nodeService; } - - /** - * Sets the file folder service - * - * @param nodeService - */ - public void setFileFolderService(FileFolderService fileFolderService) - { - this.fileFolderService = fileFolderService; - } - + /** * Sets the person service * @@ -254,79 +236,4 @@ public class Repository implements ApplicationContextAware, ApplicationListener return (NodeRef)nodeService.getProperty(person, ContentModel.PROP_HOMEFOLDER); } - /** - * Helper to convert a Web Script Request URL to a Node Ref - * - * 1) Node - {store_type}/{store_id}/{node_id} - * - * Resolve to node via its Node Reference. - * - * 2) Path - {store_type}/{store_id}/{path} - * - * Resolve to node via its display path. - * - * 3) QName - {store_type}/{store_id}/{child_qname_path} TODO: Implement - * - * Resolve to node via its child qname path. - * - * @param referenceType one of node, path or qname - * @return reference array of reference segments (as described above for each reference type) - */ - public NodeRef findNodeRef(String referenceType, String[] reference) - { - NodeRef nodeRef = null; - - // construct store reference - if (reference.length < 3) - { - throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Reference " + Arrays.toString(reference) + " is not properly formed"); - } - StoreRef storeRef = new StoreRef(reference[0], reference[1]); - if (nodeService.exists(storeRef)) - { - if (referenceType.equals("node")) - { - NodeRef urlRef = new NodeRef(storeRef, reference[2]); - if (nodeService.exists(urlRef)) - { - nodeRef = urlRef; - } - } - - else if (referenceType.equals("path")) - { - // TODO: Allow a root path to be specified - for now, hard-code to Company Home -// NodeRef rootNodeRef = nodeService.getRootNode(storeRef); - NodeRef rootNodeRef = getCompanyHome(); - if (reference.length == 3) - { - nodeRef = rootNodeRef; - } - else - { - String[] path = new String[reference.length - /*2*/3]; - System.arraycopy(reference, /*2*/3, path, 0, path.length); - - try - { - FileInfo fileInfo = fileFolderService.resolveNamePath(rootNodeRef, Arrays.asList(path)); - nodeRef = fileInfo.getNodeRef(); - } - catch (FileNotFoundException e) - { - // NOTE: return null node ref - } - } - } - - else - { - // TODO: Implement 'qname' style - throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script Node URL specified an invalid reference style of '" + referenceType + "'"); - } - } - - return nodeRef; - } - } diff --git a/source/java/org/alfresco/web/scripts/WebScriptDescription.java b/source/java/org/alfresco/web/scripts/WebScriptDescription.java new file mode 100644 index 0000000000..39fdfdadc2 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptDescription.java @@ -0,0 +1,196 @@ +/* + * 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.InputStream; + + +/** + * Web Script Description + * + * @author davidc + */ +public interface WebScriptDescription +{ + /** + * Enumeration of "required" Authentication level + */ + public enum RequiredAuthentication + { + none, + guest, + user, + admin + } + + /** + * Enumeration of "required" Transaction level + */ + public enum RequiredTransaction + { + none, + required, + requiresnew + } + + /** + * Caching requirements + */ + public interface RequiredCache + { + /** + * Determine if Web Script should ever be cached + * + * @return true => do not cache, false => caching may or not occur + */ + public boolean getNeverCache(); + + /** + * Determine if Web Script content is for public caching + * + * @return true => content is public, so allow cache + */ + public boolean getIsPublic(); + + /** + * Must cache re-validate to ensure content is fresh + * + * @return true => must re-validate + */ + public boolean getMustRevalidate(); + } + + /** + * Enumeration of ways to specify format + */ + public enum FormatStyle + { + any, // any of the following styles + extension, // /a/b/c.x + argument // /a/b/c?format=x + } + + + /** + * Gets the root path of the store of this web script + * + * @return root path of store + */ + public String getStorePath(); + + /** + * Gets the path within the store of this web script + * + * @return path within store + */ + public String getScriptPath(); + + /** + * Gets the path of the description xml document for this web script + * + * @return document location (path) + */ + public String getDescPath(); + + /** + * Gets the description xml document for this web script + * + * @return source document + */ + public InputStream getDescDocument() + throws IOException; + + /** + * Gets the id of this service + * + * @return service id + */ + public String getId(); + + /** + * Gets the short name of this service + * + * @return service short name + */ + public String getShortName(); + + /** + * Gets the description of this service + */ + public String getDescription(); + + /** + * Gets the required authentication level for execution of this service + * + * @return the required authentication level + */ + public RequiredAuthentication getRequiredAuthentication(); + + /** + * Gets the required transaction level + * + * @return the required transaction level + */ + public RequiredTransaction getRequiredTransaction(); + + /** + * Gets the required level of caching + * @return + */ + public RequiredCache getRequiredCache(); + + /** + * Gets the HTTP method this service is bound to + * + * @return HTTP method + */ + public String getMethod(); + + /** + * Gets the URIs this service supports + * + * @return array of URIs in order specified in service description document + */ + public String[] getURIs(); + + /** + * Gets the style of Format discriminator supported by this web script + * + * @return format style + */ + public FormatStyle getFormatStyle(); + + /** + * Gets the default response format + * + * Note: the default response format is the first listed in the service + * description document + * + * @return default response format (or null, if format not known until run-time) + */ + public String getDefaultFormat(); + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptDescriptionImpl.java b/source/java/org/alfresco/web/scripts/WebScriptDescriptionImpl.java new file mode 100644 index 0000000000..c6ed8452c8 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptDescriptionImpl.java @@ -0,0 +1,296 @@ +/* + * 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.InputStream; + + +/** + * Implementation of a Web Script Description + * + * @author davidc + */ +public class WebScriptDescriptionImpl implements WebScriptDescription +{ + private WebScriptStore store; + private String scriptPath; + private String descPath; + private String id; + private String shortName; + private String description; + private RequiredAuthentication requiredAuthentication; + private RequiredTransaction requiredTransaction; + private RequiredCache requiredCache; + private FormatStyle formatStyle; + private String httpMethod; + private String[] uris; + private String defaultFormat; + + + /** + * Sets the web description store + * + * @param store store + */ + public void setStore(WebScriptStore store) + { + this.store = store; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getStorePath() + */ + public String getStorePath() + { + return store.getBasePath(); + } + + /** + * Sets the script path + * + * @param scriptPath + */ + public void setScriptPath(String scriptPath) + { + this.scriptPath = scriptPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getScriptPath() + */ + public String getScriptPath() + { + return scriptPath; + } + + /** + * Sets the desc path + * + * @param descPath + */ + public void setDescPath(String descPath) + { + this.descPath = descPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getDescPath() + */ + public String getDescPath() + { + return descPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getDescDocument() + */ + public InputStream getDescDocument() + throws IOException + { + return store.getDocument(descPath); + } + + /** + * Sets the service id + * + * @param id + */ + public void setId(String id) + { + this.id = id; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getId() + */ + public String getId() + { + return this.id; + } + + /** + * Sets the service short name + * + * @param shortName + */ + public void setShortName(String shortName) + { + this.shortName = shortName; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getShortName() + */ + public String getShortName() + { + return this.shortName; + } + + /** + * Sets the service description + * + * @param description + */ + public void setDescription(String description) + { + this.description = description; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getDescription() + */ + public String getDescription() + { + return this.description; + } + + /** + * Sets the required level of authentication + * + * @param requiredAuthentication + */ + public void setRequiredAuthentication(RequiredAuthentication requiredAuthentication) + { + this.requiredAuthentication = requiredAuthentication; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getRequiredAuthentication() + */ + public RequiredAuthentication getRequiredAuthentication() + { + return this.requiredAuthentication; + } + + /** + * Sets the required level of transaction + * + * @param requiredTransaction + */ + public void setRequiredTransaction(RequiredTransaction requiredTransaction) + { + this.requiredTransaction = requiredTransaction; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getRequiredTransaction() + */ + public RequiredTransaction getRequiredTransaction() + { + return this.requiredTransaction; + } + + /** + * Sets the required cache + * + * @param requiredCache + */ + public void setRequiredCache(RequiredCache requiredCache) + { + this.requiredCache = requiredCache; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getRequiredCache() + */ + public RequiredCache getRequiredCache() + { + return this.requiredCache; + } + + /** + * Sets the format style + * + * @param formatStyle + */ + public void setFormatStyle(FormatStyle formatStyle) + { + this.formatStyle = formatStyle; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getFormatStyle() + */ + public FormatStyle getFormatStyle() + { + return this.formatStyle; + } + + /** + * Sets the service http method + * + * @param httpMethod + */ + public void setMethod(String httpMethod) + { + this.httpMethod = httpMethod; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getMethod() + */ + public String getMethod() + { + return this.httpMethod; + } + + /** + * Sets the service URIs + * + * @param uris + */ + public void setUris(String[] uris) + { + this.uris = uris; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getURIs() + */ + public String[] getURIs() + { + return this.uris; + } + + /** + * Sets the default response format + * + * @param defaultFormat + */ + public void setDefaultFormat(String defaultFormat) + { + this.defaultFormat = defaultFormat; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptDescription#getDefaultFormat() + */ + public String getDefaultFormat() + { + return this.defaultFormat; + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptException.java b/source/java/org/alfresco/web/scripts/WebScriptException.java new file mode 100644 index 0000000000..bc7ec77c6e --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptException.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Web Script Exceptions. + * + * @author David Caruana + */ +public class WebScriptException extends AlfrescoRuntimeException +{ + private static final long serialVersionUID = -7338963365877285084L; + + private int status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + + + public WebScriptException(int status, String msgId) + { + this(msgId); + this.status = status; + } + + public WebScriptException(String msgId) + { + super(msgId); + } + + public WebScriptException(String msgId, Throwable cause) + { + super(msgId, cause); + } + + public WebScriptException(String msgId, Object ... args) + { + super(msgId, args); + } + + public WebScriptException(String msgId, Throwable cause, Object ... args) + { + super(msgId, args, cause); + } + + public int getStatus() + { + return status; + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptMatch.java b/source/java/org/alfresco/web/scripts/WebScriptMatch.java new file mode 100644 index 0000000000..90cc97e12b --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptMatch.java @@ -0,0 +1,62 @@ +/* + * 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; + + +/** + * Represents a URL request to Web Script match + * + * @author davidc + */ +public interface WebScriptMatch +{ + public enum Kind + { + /** URL request matches on URI only */ + URI, + /** URL request matches on URI and Method */ + FULL + }; + + /** + * Gets the kind of Match + */ + public Kind getKind(); + + /** + * Gets the part of the request URL that matched the Web Script URL Template + * + * @return matching url path + */ + public String getPath(); + + /** + * Gets the matching web script + * + * @return service (or null, if match kind is URI) + */ + public WebScript getWebScript(); + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptPath.java b/source/java/org/alfresco/web/scripts/WebScriptPath.java new file mode 100644 index 0000000000..821497ea1f --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptPath.java @@ -0,0 +1,70 @@ +/* + * 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; + + +/** + * Web Script Path + * + * @author davidc + */ +public interface WebScriptPath +{ + /** + * Gets the full path + * + * @return path + */ + public String getPath(); + + /** + * Gets the name of the path (last path segment) + * + * @return name + */ + public String getName(); + + /** + * Gets the parent path + * + * @return path + */ + public WebScriptPath getParent(); + + /** + * Gets the child paths + * + * @return child paths + */ + public WebScriptPath[] getChildren(); + + /** + * Gets Web Scripts associated with this path + * + * @return web scripts + */ + public WebScript[] getScripts(); + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptRegistry.java b/source/java/org/alfresco/web/scripts/WebScriptRegistry.java new file mode 100644 index 0000000000..310653cff0 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptRegistry.java @@ -0,0 +1,120 @@ +/* + * 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.Collection; + +import javax.servlet.ServletContext; + +import org.alfresco.service.cmr.repository.TemplateImageResolver; + + +/** + * Web Scripts Registry + * + * @author davidc + */ +public interface WebScriptRegistry +{ + /** + * Gets a Web Script Package + * + * @param packagePath + * @return web script path representing package + */ + public WebScriptPath getPackage(String packagePath); + + /** + * Gets a Web Script URL + * + * @param uriPath + * @return web script path representing uri + */ + public WebScriptPath getUri(String uriPath); + + /** + * Gets all Web Scripts + * + * @return web scripts + */ + public Collection getWebScripts(); + + /** + * Gets a Web Script by Id + * + * @param id web script id + * @return web script + */ + public WebScript getWebScript(String id); + + /** + * Gets a Web Script given an HTTP Method and URI + * + * @param method http method + * @param uri uri + * @return service match (pair of service and uri that matched) + */ + public WebScriptMatch findWebScript(String method, String uri); + + /** + * Gets the Servlet Context + * + * @return servlet context + */ + public ServletContext getContext(); + + /** + * Gets the response format registry + * + * @return response format registry + */ + public FormatRegistry getFormatRegistry(); + + /** + * Gets the Template Processor + * + * @return template processor + */ + public TemplateProcessor getTemplateProcessor(); + + /** + * Gets the Template Image Resolver + * + * @return template image resolver + */ + public TemplateImageResolver getTemplateImageResolver(); + + /** + * Gets the Script Processor + * + * @return script processor + */ + public ScriptProcessor getScriptProcessor(); + + /** + * Resets the Registry + */ + public void reset(); +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptRequest.java b/source/java/org/alfresco/web/scripts/WebScriptRequest.java new file mode 100644 index 0000000000..38eaf782c9 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptRequest.java @@ -0,0 +1,199 @@ +/* + * 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.web.scripts.WebScriptDescription.FormatStyle; + + +/** + * Web Script Request + * + * @author davidc + */ +public interface WebScriptRequest +{ + /** + * Gets the matching API Service for this request + * + * @return the service match + */ + public WebScriptMatch getServiceMatch(); + + /** + * Get server portion of the request + * + * e.g. scheme://host:port + * + * @return server path + */ + public String getServerPath(); + + /** + * Gets the Alfresco Context Path + * + * @return context url e.g. /alfresco + */ + public String getContextPath(); + + /** + * Gets the Alfresco Web Script Context Path + * + * @return service url e.g. /alfresco/service + */ + public String getServiceContextPath(); + + /** + * Gets the Alfresco Service Path + * + * @return service url e.g. /alfresco/service/search/keyword + */ + public String getServicePath(); + + /** + * Gets the full request URL + * + * @return request url e.g. /alfresco/service/search/keyword?q=term + */ + public String getURL(); + + /** + * Gets the service specific path + * + * @return request path e.g. /search/keyword + */ + public String getPathInfo(); + + /** + * Gets the query String + * + * @return query string e.g. q=alfresco&format=atom + */ + public String getQueryString(); + + /** + * Gets the names of all parameters on the Url + * + * @return the names (empty, if none) + */ + public String[] getParameterNames(); + + /** + * Gets the value of the named parameter + * + * @param name parameter name + * @return parameter value (or null, if parameter does not exist) + */ + public String getParameter(String name); + + /** + * Gets the (array) value of the named parameter + * + * Note: An array of one item is returned when a "single value" named parameter + * is requested + * + * @param name parameter name + * @return array of values (or null, if parameter does not exist) + */ + public String[] getParameterValues(String name); + + /** + * + * @return + */ + public String[] getAttributeNames(); + + /** + * + * @param name + * @return + */ + public Object getAttribute(String name); + + /** + * + * @return + */ + public Object[] getAttributeValues(); + + /** + * Gets the path extension beyond the path registered for this service + * + * e.g. + * a) service registered path = /search/engine + * b) request path = /search/engine/external + * + * => /external + * + * @return extension path + */ + public String getExtensionPath(); + + /** + * Determine if Guest User? + * + * @return true => guest user + */ + public boolean isGuest(); + + /** + * Get Requested Format + * + * @return content type requested + */ + public String getFormat(); + + /** + * Get the style the Format was specified in + * + * @return format style (excludes any) + */ + public FormatStyle getFormatStyle(); + + /** + * Get User Agent + * + * TODO: Expand on known agents + * + * @return MSIE / Firefox + */ + public String getAgent(); + + /** + * Get the JSON callback method + * + * @return method (or null, if not specified) + */ + public String getJSONCallback(); + + /** + * Force response to return SUCCESS (200) code + * + * Note: This is to support clients who cannot support non-success codes + * e.g. Flash player + * + * @return true => force return of 200, otherwise return status explicitly set + */ + public boolean forceSuccessStatus(); +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptRequestImpl.java b/source/java/org/alfresco/web/scripts/WebScriptRequestImpl.java new file mode 100644 index 0000000000..e55df3cfc7 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptRequestImpl.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 org.alfresco.web.scripts.WebScriptDescription.FormatStyle; + + +/** + * Basic Implementation of a Web Script Request + * + * @author davidc + */ +public abstract class WebScriptRequestImpl implements WebScriptRequest +{ + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getExtensionPath() + */ + public String getExtensionPath() + { + String extensionPath = ""; + WebScriptMatch match = getServiceMatch(); + if (match != null) + { + String matchPath = getServiceMatch().getPath(); + String pathInfo = getPathInfo(); + if (pathInfo != null) + { + extensionPath = pathInfo.substring(matchPath.length()); + } + } + return extensionPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#isGuest() + */ + public boolean isGuest() + { + return Boolean.valueOf(getParameter("guest")); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getFormat() + */ + public String getFormat() + { + String format = null; + WebScriptMatch match = getServiceMatch(); + if (match != null) + { + FormatStyle style = getServiceMatch().getWebScript().getDescription().getFormatStyle(); + + // extract format from extension + if (style == FormatStyle.extension || style == FormatStyle.any) + { + String pathInfo = getPathInfo(); + if (pathInfo != null) + { + int extIdx = pathInfo.lastIndexOf('.'); + if (extIdx != -1) + { + format = pathInfo.substring(extIdx +1); + } + } + } + + // extract format from argument + if (style == FormatStyle.argument || style == FormatStyle.any) + { + String argFormat = getParameter("format"); + if (argFormat != null) + { + if (format != null && format.length() > 0) + { + throw new WebScriptException("Format specified both in extension and format argument"); + } + format = argFormat; + } + } + } + + return (format == null || format.length() == 0) ? "" : format; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getFormatStyle() + */ + public FormatStyle getFormatStyle() + { + WebScriptMatch match = getServiceMatch(); + if (match == null) + { + return FormatStyle.any; + } + FormatStyle style = match.getWebScript().getDescription().getFormatStyle(); + if (style != FormatStyle.any) + { + return style; + } + else + { + String argFormat = getParameter("format"); + if (argFormat != null && argFormat.length() > 0) + { + return FormatStyle.argument; + } + else + { + return FormatStyle.extension; + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getJSONCallback() + */ + public String getJSONCallback() + { + return getParameter("alf_callback"); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#forceSuccessStatus() + */ + public boolean forceSuccessStatus() + { + return false; + } +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptResponse.java b/source/java/org/alfresco/web/scripts/WebScriptResponse.java new file mode 100644 index 0000000000..acc764ff83 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptResponse.java @@ -0,0 +1,108 @@ +/* + * 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; + + +/** + * Web Script Response + * + * @author davidc + */ +public interface WebScriptResponse +{ + // 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"; + + /** + * Sets the Response Status + * + * @param status + */ + public void setStatus(int status); + + /** + * Sets the Content Type + * + * @param contentType + */ + public void setContentType(String contentType); + + /** + * Sets the Cache control + * + * @param cache cache control + */ + public void setCache(WebScriptCache cache); + + /** + * Gets the Writer + * + * @return writer + * @throws IOException + */ + public Writer getWriter() throws IOException; + + /** + * Gets the Output Stream + * + * @return output stream + * @throws IOException + */ + public OutputStream getOutputStream() throws IOException; + + /** + * Clears response buffer + */ + public void reset(); + + /** + * Encode a script URL + * + * Note: Some Web Script Runtime environments (e.g. JSR-168, JSF) require urls to be re-written. + * + * @param url to encode + * @return encoded url + */ + public String encodeScriptUrl(String url); + + /** + * Return a client side javascript function to build urls to this service + * + * @param name Generated function name + * + * @return javascript function definition + */ + public String getEncodeScriptUrlFunction(String name); + +} 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..3a9d266143 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptRuntime.java @@ -0,0 +1,453 @@ +/* + * 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.PrintWriter; +import java.io.StringWriter; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.security.AuthorityService; +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 ServiceRegistry serviceRegistry; + private RetryingTransactionHelper retryingTransactionHelper; + private AuthorityService authorityService; + + /** + * Construct + * + * @param registry web script registry + * @param serviceRegistry service registry + */ + public WebScriptRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry) + { + this.registry = registry; + this.serviceRegistry = serviceRegistry; + this.authorityService = serviceRegistry.getAuthorityService(); + this.retryingTransactionHelper = serviceRegistry.getRetryingTransactionHelper(); + } + + /** + * Execute the Web Script encapsulated by this Web Script Runtime + */ + public void executeScript() + { + long startRuntime = System.currentTimeMillis(); + + String method = getScriptMethod(); + String scriptUrl = null; + + try + { + // extract script url + scriptUrl = getScriptUrl(); + if (scriptUrl == null || scriptUrl.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Script URL not specified"); + } + + if (logger.isDebugEnabled()) + logger.debug("Processing script url (" + method + ") " + scriptUrl); + + WebScriptMatch match = registry.findWebScript(method, scriptUrl); + if (match == null || match.getKind() == WebScriptMatch.Kind.URI) + { + if (match == null) + { + String msg = "Script url " + scriptUrl + " does not map to a Web Script."; + if (logger.isDebugEnabled()) + logger.debug(msg); + throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, msg); + } + else + { + String msg = "Script url " + scriptUrl + " does not support the method " + method; + if (logger.isDebugEnabled()) + logger.debug(msg); + throw new WebScriptException(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); + } + } + + // create web script request & response + 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(); + String reqFormat = scriptReq.getFormat(); + String format = (reqFormat == null || reqFormat.length() == 0) ? "default" : scriptReq.getFormat(); + WebScriptDescription desc = scriptReq.getServiceMatch().getWebScript().getDescription(); + logger.debug("Format style: " + desc.getFormatStyle() + ", Default format: " + desc.getDefaultFormat()); + logger.debug("Invoking Web Script " + description.getId() + (user == null ? " (unauthenticated)" : " (authenticated as " + user + ") (format " + format + ") (" + locale + ")")); + } + + // execute script within required level of authentication + authenticatedExecute(scriptReq, scriptRes); + } + finally + { + if (logger.isDebugEnabled()) + { + long endScript = System.currentTimeMillis(); + logger.debug("Web Script " + description.getId() + " executed in " + (endScript - startScript) + "ms"); + } + } + } + catch(Throwable e) + { + if (logger.isInfoEnabled()) + logger.info("Caught exception & redirecting to status template: " + e.getMessage()); + if (logger.isDebugEnabled()) + { + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + e.printStackTrace(printWriter); + logger.debug("Caught exception: " + writer.toString()); + } + + // extract status code, if specified + int statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + if (e instanceof WebScriptException) + { + statusCode = ((WebScriptException)e).getStatus(); + } + + // create web script status for status template rendering + WebScriptStatus status = new WebScriptStatus(); + status.setCode(statusCode); + status.setMessage(e.getMessage()); + status.setException(e); + + // create basic model for status template rendering + WebScriptRequest req = createRequest(null); + WebScriptResponse res = createResponse(); + Map model = new HashMap(); + model.put("status", status); + model.put("url", new URLModel(req)); + model.put("server", new ServerModel(serviceRegistry.getDescriptorService().getServerDescriptor())); + model.put("date", new Date()); + + // locate status template + // NOTE: search order... + // 1) root located .ftl + // 2) root located status.ftl + String templatePath = getStatusCodeTemplate(statusCode); + if (!registry.getTemplateProcessor().hasTemplate(templatePath)) + { + templatePath = getStatusTemplate(); + if (!registry.getTemplateProcessor().hasTemplate(templatePath)) + { + throw new WebScriptException("Failed to find status template " + templatePath + " (format: " + WebScriptResponse.HTML_FORMAT + ")"); + } + } + + // render output + if (logger.isDebugEnabled()) + { + logger.debug("Force success status header in response: " + req.forceSuccessStatus()); + logger.debug("Sending status " + statusCode + " (Template: " + templatePath + ")"); + logger.debug("Rendering response: content type=" + MimetypeMap.MIMETYPE_HTML); + } + + res.reset(); + WebScriptCache cache = new WebScriptCache(); + cache.setNeverCache(true); + res.setCache(cache); + res.setStatus(req.forceSuccessStatus() ? HttpServletResponse.SC_OK : statusCode); + res.setContentType(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8"); + try + { + registry.getTemplateProcessor().process(templatePath, model, res.getWriter()); + } + catch (IOException e1) + { + throw new WebScriptException("Internal error", e1); + } + } + 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) + { + transactionedExecute(scriptReq, scriptRes); + } + else if ((required == RequiredAuthentication.user || required == RequiredAuthentication.admin) && isGuest) + { + throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "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 + // + if (authenticate(required, isGuest, scriptReq, scriptRes)) + { + if (required == RequiredAuthentication.admin && !authorityService.hasAdminAuthority()) + { + throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, "Web Script " + desc.getId() + " requires admin authentication; however, a non-admin has attempted access."); + } + + // Execute Web Script + transactionedExecute(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 script within required level of transaction + * + * @param scriptReq + * @param scriptRes + * @throws IOException + */ + protected void transactionedExecute(final WebScriptRequest scriptReq, final WebScriptResponse scriptRes) + throws IOException + { + final WebScript script = scriptReq.getServiceMatch().getWebScript(); + final WebScriptDescription description = script.getDescription(); + if (description.getRequiredTransaction() == RequiredTransaction.none) + { + wrappedExecute(scriptReq, scriptRes); + } + else + { + // encapsulate script within transaction + RetryingTransactionCallback work = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + if (logger.isDebugEnabled()) + logger.debug("Begin transaction: " + description.getRequiredTransaction()); + + wrappedExecute(scriptReq, scriptRes); + + if (logger.isDebugEnabled()) + logger.debug("End transaction: " + description.getRequiredTransaction()); + + return null; + } + }; + + if (description.getRequiredTransaction() == RequiredTransaction.required) + { + retryingTransactionHelper.doInTransaction(work); + } + else + { + retryingTransactionHelper.doInTransaction(work, false, true); + } + } + } + + /** + * 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 + * + * @return true if authorised, false otherwise + */ + // TODO: DC - This method to be refactored during Web Script F/W extraction + protected abstract boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res); + + /** + * Pre-execution hook + * + * @param scriptReq Web Script Request + * @param scriptRes Web Script Response + * @return true => execute script, false => do not execute script + */ + protected boolean preExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + return true; + } + + /** + * 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 void postExecute(WebScriptRequest scriptReq, WebScriptResponse scriptRes) + { + } + + protected String getStatusCodeTemplate(int statusCode) + { + return "/" + statusCode + ".ftl"; + } + + protected String getStatusTemplate() + { + return "/status.ftl"; + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServlet.java b/source/java/org/alfresco/web/scripts/WebScriptServlet.java new file mode 100644 index 0000000000..42d822967a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServlet.java @@ -0,0 +1,132 @@ +/* + * 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 javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.config.Config; +import org.alfresco.config.ConfigService; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + + +/** + * Entry point for Web Scripts + * + * @author davidc + */ +public class WebScriptServlet extends HttpServlet +{ + private static final long serialVersionUID = 4209892938069597860L; + + // Logger + private static final Log logger = LogFactory.getLog(WebScriptServlet.class); + + // Component Dependencies + protected DeclarativeWebScriptRegistry registry; + protected ServiceRegistry serviceRegistry; + protected WebScriptServletAuthenticator authenticator; + protected ConfigService configService; + + /** Host Server Configuration */ + protected static ServerConfigElement serverConfig; + + + @Override + public void init() throws ServletException + { + super.init(); + ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); + registry = (DeclarativeWebScriptRegistry)context.getBean("webscripts.registry"); + serviceRegistry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY); + configService = (ConfigService)context.getBean("webClientConfigService"); + + // retrieve authenticator via servlet initialisation parameter + String authenticatorId = getInitParameter("authenticator"); + if (authenticatorId == null || authenticatorId.length() == 0) + { + authenticatorId = getDefaultAuthenticator(); + } + 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; + + // retrieve host server configuration + Config config = configService.getConfig("Server"); + serverConfig = (ServerConfigElement)config.getConfigElement(ServerConfigElement.CONFIG_ELEMENT_ID); + + // servlet specific initialisation + initServlet(context); + } + + + /* + * (non-Javadoc) + * + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + if (req.getCharacterEncoding() == null) + { + req.setCharacterEncoding("UTF-8"); + } + WebScriptRuntime runtime = new WebScriptServletRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig); + runtime.executeScript(); + } + + /** + * Servlet specific initialisation + * + * @param context + */ + protected void initServlet(ApplicationContext context) + { + // NOOP + } + + /** + * @return default authenticator (bean name) + */ + protected String getDefaultAuthenticator() + { + return "webscripts.authenticator.webclient"; + } +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java new file mode 100644 index 0000000000..093954f25d --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletAuthenticator.java @@ -0,0 +1,48 @@ +/* + * 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.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 + * + * @return true if authorised to execute the script, false otherwise + */ + // TODO: DC - This method to be refactored during Web Script F/W extraction + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest req, WebScriptServletResponse res); +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java new file mode 100644 index 0000000000..9263afa72a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java @@ -0,0 +1,357 @@ +/* + * 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.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.web.config.ServerConfigElement; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * HTTP Servlet Web Script Request + * + * @author davidc + */ +public class WebScriptServletRequest extends WebScriptRequestImpl +{ + // Logger + private static final Log logger = LogFactory.getLog(WebScriptServletRequest.class); + + /** Server Config */ + private ServerConfigElement serverConfig; + + /** HTTP Request */ + private HttpServletRequest req; + + /** Service bound to this request */ + private WebScriptMatch serviceMatch; + + /** Form data associated with multipart/form-data */ + private FormData formData; + + + /** + * Construct + * + * @param req + * @param serviceMatch + */ + public WebScriptServletRequest(HttpServletRequest req, WebScriptMatch serviceMatch) + { + this(null, req, serviceMatch); + } + + /** + * Construct + * + * @param serverConfig + * @param req + * @param serviceMatch + */ + public WebScriptServletRequest(ServerConfigElement serverConfig, HttpServletRequest req, WebScriptMatch serviceMatch) + { + this.serverConfig = serverConfig; + this.req = req; + this.serviceMatch = serviceMatch; + String contentType = req.getContentType(); + + if (logger.isDebugEnabled()) + logger.debug("Content Type: " + contentType); + + if (contentType != null && contentType.startsWith("multipart/form-data")) + { + formData = new FormData(req); + } + } + + /** + * Gets the HTTP Servlet Request + * + * @return HTTP Servlet Request + */ + public HttpServletRequest getHttpServletRequest() + { + 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 getServerScheme() + "://" + getServerName() + ":" + getServerPort(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getContextPath() + */ + public String getContextPath() + { + return req.getContextPath(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServiceContextPath() + */ + public String getServiceContextPath() + { + return req.getContextPath() + req.getServletPath(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServicePath() + */ + public String getServicePath() + { + String pathInfo = getPathInfo(); + return getServiceContextPath() + ((pathInfo == null) ? "" : pathInfo); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getURL() + */ + public String getURL() + { + return getServicePath() + (req.getQueryString() != null ? "?" + req.getQueryString() : ""); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getPathInfo() + */ + public String getPathInfo() + { + // NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat + String requestURI = req.getRequestURI(); + String pathInfo = requestURI.substring(getServiceContextPath().length()); + try + { + return URLDecoder.decode(pathInfo, "UTF-8"); + } + catch(UnsupportedEncodingException e) + { + throw new WebScriptException("Failed to retrieve path info", e); + } + } + + /* (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() + { + if (formData == null) + { + Set keys = req.getParameterMap().keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } + else + { + Set keys = formData.getParameters().keySet(); + String[] names = new String[keys.size()]; + keys.toArray(names); + return names; + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getParameter(java.lang.String) + */ + public String getParameter(String name) + { + if (formData == null) + { + return req.getParameter(name); + } + else + { + return formData.getParameters().get(name); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getArrayParameter(java.lang.String) + */ + public String[] getParameterValues(String name) + { + if (formData == null) + { + return req.getParameterValues(name); + } + else + { + String value = formData.getParameters().get(name); + return (value == null ) ? new String[] {} : new String[] {value}; + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return new String[0]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return new String[0]; + } + + /** + * Get User Agent + * + * TODO: Expand on known agents + * + * @return MSIE / Firefox + */ + public String getAgent() + { + String userAgent = req.getHeader("user-agent"); + if (userAgent != null) + { + if (userAgent.indexOf("Firefox/") != -1) + { + return "Firefox"; + } + else if (userAgent.indexOf("MSIE") != -1) + { + return "MSIE"; + } + } + return null; + } + + /** + * Get Server Scheme + * + * @return server scheme + */ + private String getServerScheme() + { + String scheme = null; + if (serverConfig != null) + { + scheme = serverConfig.getScheme(); + } + if (scheme == null) + { + scheme = req.getScheme(); + } + return scheme; + } + + /** + * Get Server Name + * + * @return server name + */ + private String getServerName() + { + String name = null; + if (serverConfig != null) + { + name = serverConfig.getHostName(); + } + if (name == null) + { + name = req.getServerName(); + } + return name; + } + + /** + * Get Server Port + * + * @return server name + */ + private int getServerPort() + { + Integer port = null; + if (serverConfig != null) + { + port = serverConfig.getPort(); + } + if (port == null) + { + port = req.getServerPort(); + } + return port; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequestImpl#forceSuccessStatus() + */ + @Override + public boolean forceSuccessStatus() + { + String forceSuccess = req.getHeader("alf-force-success-response"); + return Boolean.valueOf(forceSuccess); + } + + /** + * Gets the Form data associated with this request + * + * @return form data, or null if request is not multipart/form-data encoded + */ + public FormData getFormData() + { + return formData; + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java b/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java new file mode 100644 index 0000000000..34874f9919 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletResponse.java @@ -0,0 +1,218 @@ +/* + * 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 java.text.SimpleDateFormat; +import java.util.TimeZone; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.util.CachingDateFormat; +import org.alfresco.web.ui.common.Utils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * HTTP Servlet Web Script Response + * + * @author davidc + */ +public class WebScriptServletResponse implements WebScriptResponse +{ + // Logger + private static final Log logger = LogFactory.getLog(WebScriptServletResponse.class); + + // Servlet Response + 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#setStatus(int) + */ + public void setStatus(int status) + { + res.setStatus(status); + } + + /* (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#setCache(org.alfresco.web.scripts.WebScriptCache) + */ + public void setCache(WebScriptCache cache) + { + // set Cache-Control + String cacheControl = ""; + String pragma = ""; + if (cache.getIsPublic()) + { + cacheControl += "public"; + } + if (cache.getNeverCache()) + { + cacheControl += (cacheControl.length() > 0 ? ", " : "") + "no-cache"; + pragma += (pragma.length() > 0) ? ", " : "" + "no-cache"; + } + if (cache.getMaxAge() != null && cache.getNeverCache() == false) + { + cacheControl += (cacheControl.length() > 0 ? ", " : "") + " max-age=" + cache.getMaxAge(); + } + if (cache.getMustRevalidate() && cache.getNeverCache() == false) + { + cacheControl += (cacheControl.length() > 0 ? ", " : "") + " must-revalidate"; + } + if (cacheControl.length() > 0) + { + res.setHeader("Cache-Control", cacheControl); + if (logger.isDebugEnabled()) + logger.debug("Cache - set response header Cache-Control: " + cacheControl); + } + if (pragma.length() > 0) + { + res.setHeader("Pragma", pragma); + if (logger.isDebugEnabled()) + logger.debug("Cache - set response header Pragma: " + pragma); + } + + // set ETag + if (cache.getETag() != null) + { + String eTag = "\"" + cache.getETag() + "\""; + res.setHeader("ETag", eTag); + if (logger.isDebugEnabled()) + logger.debug("Cache - set response header ETag: " + eTag); + } + + // set Last Modified + if (cache.getLastModified() != null) + { + res.setDateHeader("Last-Modified", cache.getLastModified().getTime()); + if (logger.isDebugEnabled()) + { + SimpleDateFormat formatter = getHTTPDateFormat(); + String lastModified = formatter.format(cache.getLastModified()); + logger.debug("Cache - set response header Last-Modified: " + lastModified); + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#reset() + */ + public void reset() + { + try + { + res.reset(); + } + catch(IllegalStateException e) + { + } + } + + /* (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; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getEncodeScriptUrlFunction(java.lang.String) + */ + public String getEncodeScriptUrlFunction(String name) + { + return Utils.encodeJavascript(ENCODE_FUNCTION.replace("$name$", name)); + } + + private static final String ENCODE_FUNCTION = "{ $name$: function(url) { return url; } }"; + + /** + * Helper to return a HTTP Date Formatter + * + * @return HTTP Date Formatter + */ + private static SimpleDateFormat getHTTPDateFormat() + { + if (s_dateFormat.get() != null) + { + return s_dateFormat.get(); + } + + SimpleDateFormat formatter = CachingDateFormat.getDateFormat("EEE, dd MMM yyyy kk:mm:ss zzz", false); + formatter.setTimeZone(TimeZone.getTimeZone("GMT")); + s_dateFormat.set(formatter); + return s_dateFormat.get(); + } + + private static ThreadLocal s_dateFormat = new ThreadLocal(); + +} 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..f4fff0112a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRuntime.java @@ -0,0 +1,149 @@ +/* + * 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.UnsupportedEncodingException; +import java.net.URLDecoder; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; + + +/** + * HTTP Servlet Web Script Runtime + * + * @author davidc + */ +public class WebScriptServletRuntime extends WebScriptRuntime +{ + protected HttpServletRequest req; + protected HttpServletResponse res; + protected WebScriptServletAuthenticator authenticator; + protected ServerConfigElement serverConfig; + + + /** + * Construct + * + * @param registry + * @param serviceRegistry + * @param authenticator + * @param req + * @param res + */ + public WebScriptServletRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry, WebScriptServletAuthenticator authenticator, + HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig) + { + super(registry, serviceRegistry); + this.req = req; + this.res = res; + this.authenticator = authenticator; + this.serverConfig = serverConfig; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptMethod() + */ + @Override + protected String getScriptMethod() + { + // Is this an overloaded POST request? + String method = req.getMethod(); + if (method.equalsIgnoreCase("post")) + { + boolean overloadParam = false; + String overload = req.getHeader("X-HTTP-Method-Override"); + if (overload == null || overload.length() == 0) + { + overload = req.getParameter("alf_method"); + overloadParam = true; + } + if (overload != null && overload.length() > 0) + { + if (logger.isDebugEnabled()) + logger.debug("POST is tunnelling method '" + overload + "' as specified by " + (overloadParam ? "alf_method parameter" : "X-HTTP-Method-Override header")); + + method = overload; + } + } + + return method; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + // NOTE: Don't use req.getPathInfo() - it truncates the path at first semi-colon in Tomcat + String requestURI = req.getRequestURI(); + String pathInfo = requestURI.substring((req.getContextPath() + req.getServletPath()).length()); + try + { + return URLDecoder.decode(pathInfo, "UTF-8"); + } + catch(UnsupportedEncodingException e) + { + throw new WebScriptException("Failed to retrieve path info", e); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new WebScriptServletRequest(serverConfig, 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 boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) + { + boolean authorised = true; + if (authenticator != null) + { + authorised = authenticator.authenticate(required, isGuest, (WebScriptServletRequest)req, (WebScriptServletResponse)res); + } + return authorised; + } +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptStatus.java b/source/java/org/alfresco/web/scripts/WebScriptStatus.java new file mode 100644 index 0000000000..46b41b9f01 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptStatus.java @@ -0,0 +1,178 @@ +/* + * 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 org.alfresco.i18n.I18NUtil; + + +/** + * Web Script Status + * + * Records the outcome of a Web Script. + * + * @author davidc + */ +public class WebScriptStatus +{ + private Throwable exception = null; + private int code = HttpServletResponse.SC_OK; + private String message = ""; + private boolean redirect = false; + + + /** + * @param exception + */ + public void setException(Throwable exception) + { + this.exception = exception; + } + + /** + * @return exception + */ + public Throwable getException() + { + return exception; + } + + public Throwable jsGet_exception() + { + return getException(); + } + + /** + * @param message + */ + public void setMessage(String message) + { + this.message = message; + } + + public void jsSet_message(String message) + { + setMessage(message); + } + + /** + * @return message + */ + public String getMessage() + { + return message; + } + + public String jsGet_message() + { + return getMessage(); + } + + /** + * @param redirect redirect to status code response + */ + public void setRedirect(boolean redirect) + { + this.redirect = redirect; + } + + public void jsSet_redirect(boolean redirect) + { + setRedirect(redirect); + } + + /** + * @return redirect to status code response + */ + public boolean getRedirect() + { + return redirect; + } + + public boolean jsGet_redirect() + { + return getRedirect(); + } + + /** + * @see javax.servlet.http.HTTPServletResponse + * + * @param code status code + */ + public void setCode(int code) + { + this.code = code; + } + + public void jsSet_code(int code) + { + this.code = code; + } + + /** + * @return status code + */ + public int getCode() + { + return code; + } + + public int jsGet_code() + { + return getCode(); + } + + /** + * Gets the short name of the status code + * + * @return status code name + */ + public String getCodeName() + { + return I18NUtil.getMessage("webscript.code." + code + ".name"); + } + + public String jsGet_codeName() + { + return getCodeName(); + } + + /** + * Gets the description of the status code + * + * @return status code description + */ + public String getCodeDescription() + { + return I18NUtil.getMessage("webscript.code." + code + ".description"); + } + + public String jsGet_codeDescription() + { + return getCodeDescription(); + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptStorage.java b/source/java/org/alfresco/web/scripts/WebScriptStorage.java new file mode 100644 index 0000000000..8288ad7200 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptStorage.java @@ -0,0 +1,207 @@ +/* + * 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.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.alfresco.util.AbstractLifecycleBean; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +import freemarker.cache.MultiTemplateLoader; +import freemarker.cache.TemplateLoader; + + +/** + * Web Script Storage + * + * @author davidc + */ +public class WebScriptStorage implements ApplicationContextAware, ApplicationListener +{ + private ApplicationContext applicationContext; + private ProcessorLifecycle lifecycle = new ProcessorLifecycle(); + private TemplateProcessor templateProcessor; + private ScriptProcessor scriptProcessor; + + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) + */ + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + this.applicationContext = applicationContext; + this.lifecycle.setApplicationContext(applicationContext); + } + + /* (non-Javadoc) + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + public void onApplicationEvent(ApplicationEvent event) + { + lifecycle.onApplicationEvent(event); + } + + /** + * Sets the template processor + * + * @param templateProcessor + */ + public void setTemplateProcessor(TemplateProcessor templateProcessor) + { + this.templateProcessor = templateProcessor; + } + + /** + * Sets the script processor + * + * @param scriptProcessor + */ + public void setScriptProcessor(ScriptProcessor scriptProcessor) + { + this.scriptProcessor = scriptProcessor; + } + + /** + * Gets all Web Script Stores + * + * @return all Web Script Stores + */ + @SuppressWarnings("unchecked") + public Collection getStores() + { + Collection allstores = applicationContext.getBeansOfType(WebScriptStore.class, false, false).values(); + Collection stores = new ArrayList(); + for (WebScriptStore store : allstores) + { + if (store.exists()) + { + stores.add(store); + } + } + return stores; + } + + /** + * Gets the Web Script Store for the given Store path + * + * @param storePath + * @return store (or null, if not found) + */ + public WebScriptStore getStore(String storePath) + { + Collection stores = getStores(); + for (WebScriptStore store : stores) + { + if (store.getBasePath().equals(storePath)) + { + return store; + } + } + return null; + } + + /** + * Gets the Template Processor + * + * @return template processor + */ + public TemplateProcessor getTemplateProcessor() + { + return templateProcessor; + } + + /** + * Gets the Script Processor + * + * @return script processor + */ + public ScriptProcessor getScriptProcessor() + { + return scriptProcessor; + } + + /** + * Register template loader from each Web Script Store with Template Processor + */ + protected void initTemplateProcessor() + { + List loaders = new ArrayList(); + for (WebScriptStore apiStore : getStores()) + { + TemplateLoader loader = apiStore.getTemplateLoader(); + if (loader == null) + { + throw new WebScriptException("Unable to retrieve template loader for Web Script store " + apiStore.getBasePath()); + } + loaders.add(loader); + } + MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()])); + templateProcessor.setTemplateLoader(loader); + } + + /** + * Register script loader from each Web Script Store with Script Processor + */ + protected void initScriptProcessor() + { + List loaders = new ArrayList(); + for (WebScriptStore apiStore : getStores()) + { + ScriptLoader loader = apiStore.getScriptLoader(); + if (loader == null) + { + throw new WebScriptException("Unable to retrieve script loader for Web Script store " + apiStore.getBasePath()); + } + loaders.add(loader); + } + MultiScriptLoader loader = new MultiScriptLoader(loaders.toArray(new ScriptLoader[loaders.size()])); + scriptProcessor.setScriptLoader(loader); + } + + /** + * Hooks into Spring Application Lifecycle + */ + private class ProcessorLifecycle extends AbstractLifecycleBean + { + @Override + protected void onBootstrap(ApplicationEvent event) + { + initTemplateProcessor(); + initScriptProcessor(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/WebScriptStore.java b/source/java/org/alfresco/web/scripts/WebScriptStore.java new file mode 100644 index 0000000000..6d236af9b5 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptStore.java @@ -0,0 +1,114 @@ +/* + * 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.InputStream; + +import freemarker.cache.TemplateLoader; + + +/** + * Store for holding Web Script Definitions and Implementations + * + * @author davidc + */ +public interface WebScriptStore +{ + /** + * Determines whether the store actually exists + * + * @return true => it does exist + */ + public boolean exists(); + + /** + * Gets the base path of the store + * + * @return base path + */ + public String getBasePath(); + + /** + * Gets the paths of all Web Script description documents in this store + * + * @return array of description document paths + */ + public String[] getDescriptionDocumentPaths(); + + /** + * Gets the paths of all implementation files for a given Web Script + * + * @param script web script + * @return array of implementation document paths + */ + public String[] getScriptDocumentPaths(WebScript script); + + /** + * Determines if the document exists + * + * @param documentPath document path + * @return true => exists, false => does not exist + */ + public boolean hasDocument(String documentPath); + + /** + * Gets a document + * + * @param documentPath document path + * @return input stream onto document + * + * @throws IOException + */ + public InputStream getDocument(String documentPath) + throws IOException; + + /** + * Creates a document + * + * @param documentPath + * @param content + * + * @throws IOException + */ + public void createDocument(String documentPath, String content) + throws IOException; + + /** + * Gets the template loader for this store + * + * @return template loader + */ + public TemplateLoader getTemplateLoader(); + + /** + * Gets the script loader for this store + * + * @return script loader + */ + public ScriptLoader getScriptLoader(); + +} + diff --git a/source/java/org/alfresco/web/scripts/WebScriptURLRequest.java b/source/java/org/alfresco/web/scripts/WebScriptURLRequest.java new file mode 100644 index 0000000000..06e5e69adb --- /dev/null +++ b/source/java/org/alfresco/web/scripts/WebScriptURLRequest.java @@ -0,0 +1,248 @@ +/* + * 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.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * Web Script Request implementation that acts upon a string representation + * of a URL + * + * @author davidc + */ +public abstract class WebScriptURLRequest extends WebScriptRequestImpl +{ + /** Script Url components */ + protected String contextPath; + protected String servletPath; + protected String pathInfo; + protected String queryString; + protected Map queryArgs; + protected Map> queryArgsMulti; + + /** Service bound to this request */ + protected WebScriptMatch serviceMatch; + + + /** + * Splits a Web Script Url 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[] splitURL(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 scriptUrl + * @param serviceMatch + */ + public WebScriptURLRequest(String scriptUrl, WebScriptMatch serviceMatch) + { + this(splitURL(scriptUrl), serviceMatch); + } + + /** + * Construct + * + * @param scriptUrlParts + * @param serviceMatch + */ + public WebScriptURLRequest(String[] scriptUrlParts, WebScriptMatch serviceMatch) + { + this.contextPath = scriptUrlParts[0]; + this.servletPath = scriptUrlParts[1]; + this.pathInfo = scriptUrlParts[2]; + this.queryString = scriptUrlParts[3]; + this.queryArgs = new HashMap(); + this.queryArgsMulti = new HashMap>(); + if (this.queryString != null) + { + String[] args = this.queryString.split("&"); + for (String arg : args) + { + String[] parts = arg.split("="); + if (this.queryArgs.containsKey(parts[0])) + { + List values = this.queryArgsMulti.get(parts[0]); + if (values == null) + { + values = new ArrayList(); + this.queryArgsMulti.put(parts[0], values); + } + values.add(parts.length == 2 ? parts[1] : ""); + } + else + { + this.queryArgs.put(parts[0], parts.length == 2 ? parts[1] : ""); + } + } + } + this.serviceMatch = serviceMatch; + } + + @Override + public String toString() + { + return "Request Service Match: " + serviceMatch + + " URL: " + this.contextPath + this.servletPath + this.pathInfo + "?" + queryString; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServiceMatch() + */ + public WebScriptMatch getServiceMatch() + { + return serviceMatch; + } + + /* (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#getPathInfo() + */ + public String getPathInfo() + { + return pathInfo; + } + + /* (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#getArrayParameter(java.lang.String) + */ + public String[] getParameterValues(String name) + { + List values = queryArgsMulti.get(name); + if (values != null) + { + String[] array = new String[values.size()]; + values.toArray(array); + return array; + } + else + { + String value = queryArgs.get(name); + if (value != null) + { + return new String[]{value}; + } + } + return null; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java b/source/java/org/alfresco/web/scripts/bean/ContentGet.java similarity index 82% rename from source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java rename to source/java/org/alfresco/web/scripts/bean/ContentGet.java index f69cc2f8c7..0e3dfc36fc 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/ContentGet.java +++ b/source/java/org/alfresco/web/scripts/bean/ContentGet.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.io.IOException; import java.net.SocketException; @@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.web.scripts.Repository; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; @@ -46,12 +45,12 @@ import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.web.scripts.AbstractWebScript; -import org.alfresco.web.scripts.Cache; +import org.alfresco.web.scripts.WebScriptCache; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; import org.alfresco.web.scripts.WebScriptResponse; -import org.alfresco.web.scripts.servlet.WebScriptServletRequest; -import org.alfresco.web.scripts.servlet.WebScriptServletResponse; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -68,62 +67,6 @@ public class ContentGet extends AbstractWebScript // Logger private static final Log logger = LogFactory.getLog(ContentGet.class); - // Component dependencies - private Repository repository; - private NamespaceService namespaceService; - private PermissionService permissionService; - private NodeService nodeService; - private ContentService contentService; - private MimetypeService mimetypeService; - - /** - * @param repository - */ - public void setRepository(Repository repository) - { - this.repository = repository; - } - - /** - * @param namespaceService - */ - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } - - /** - * @param permissionService - */ - public void setPermissionService(PermissionService permissionService) - { - this.permissionService = permissionService; - } - - /** - * @param nodeService - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * @param contentService - */ - public void setContentService(ContentService contentService) - { - this.contentService = contentService; - } - - /** - * @param mimetypeService - */ - public void setMimetypeService(MimetypeService mimetypeService) - { - this.mimetypeService = mimetypeService; - } - /* (non-Javadoc) * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) @@ -146,7 +89,7 @@ public class ContentGet extends AbstractWebScript String[] extParts = extensionPath == null ? new String[1] : extensionPath.split("/"); String[] path = new String[extParts.length -1]; System.arraycopy(extParts, 1, path, 0, extParts.length -1); - NodeRef nodeRef = repository.findNodeRef(matchParts[2], path); + NodeRef nodeRef = findNodeRef(matchParts[2], path); if (nodeRef == null) { throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + matchParts[2] + " reference " + Arrays.toString(path)); @@ -164,6 +107,7 @@ public class ContentGet extends AbstractWebScript String propertyName = contentPart.substring(1); if (propertyName.length() > 0) { + NamespaceService namespaceService = getServiceRegistry().getNamespaceService(); propertyQName = QName.createQName(propertyName, namespaceService); } } @@ -175,12 +119,14 @@ public class ContentGet extends AbstractWebScript logger.debug("Retrieving content from node ref " + nodeRef.toString() + " (property: " + propertyQName.toString() + ") (attach: " + attach + ")"); // check that the user has at least READ_CONTENT access - else redirect to the login page + PermissionService permissionService = getServiceRegistry().getPermissionService(); if (permissionService.hasPermission(nodeRef, PermissionService.READ_CONTENT) == AccessStatus.DENIED) { throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Permission denied"); } // check If-Modified-Since header and set Last-Modified header as appropriate + NodeService nodeService = getServiceRegistry().getNodeService(); Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); long modifiedSince = httpReq.getDateHeader("If-Modified-Since"); if (modifiedSince > 0L) @@ -203,6 +149,7 @@ public class ContentGet extends AbstractWebScript } // get the content reader + ContentService contentService = getServiceRegistry().getContentService(); ContentReader reader = contentService.getReader(nodeRef, propertyQName); if (reader == null || !reader.exists()) { @@ -213,12 +160,13 @@ public class ContentGet extends AbstractWebScript String mimetype = reader.getMimetype(); if (mimetype == null || mimetype.length() == 0) { + MimetypeService mimetypeMap = getServiceRegistry().getMimetypeService(); mimetype = MimetypeMap.MIMETYPE_BINARY; int extIndex = extensionPath.lastIndexOf('.'); if (extIndex != -1) { String ext = extensionPath.substring(extIndex + 1); - String mt = mimetypeService.getMimetypesByExtension().get(ext); + String mt = mimetypeMap.getMimetypesByExtension().get(ext); if (mt != null) { mimetype = mt; @@ -232,7 +180,7 @@ public class ContentGet extends AbstractWebScript httpRes.setHeader("Content-Length", Long.toString(reader.getSize())); // set caching - Cache cache = new Cache(); + WebScriptCache cache = new WebScriptCache(); cache.setNeverCache(false); cache.setMustRevalidate(true); cache.setLastModified(modified); diff --git a/source/java/org/alfresco/web/scripts/bean/Index.java b/source/java/org/alfresco/web/scripts/bean/Index.java new file mode 100644 index 0000000000..5a12684b68 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/Index.java @@ -0,0 +1,56 @@ +/* + * 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.bean; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; + + +/** + * Index of all Web Scripts + * + * @author davidc + */ +public class Index extends DeclarativeWebScript +{ + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + Map model = new HashMap(7, 1.0f); + model.put("webscripts", getWebScriptRegistry().getWebScripts()); + model.put("rooturl", getWebScriptRegistry().getUri("/")); + model.put("rootpackage", getWebScriptRegistry().getPackage("/")); + return model; + } + +} diff --git a/source/java/org/alfresco/web/scripts/bean/IndexPackage.java b/source/java/org/alfresco/web/scripts/bean/IndexPackage.java new file mode 100644 index 0000000000..09a0c54f42 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/IndexPackage.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptPath; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; + + +/** + * Index of a Web Script Package + * + * @author davidc + */ +public class IndexPackage extends DeclarativeWebScript +{ + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + // extract web script package + String packagePath = req.getExtensionPath(); + if (packagePath == null || packagePath.length() == 0) + { + packagePath = "/"; + } + if (!packagePath.startsWith("/")) + { + packagePath = "/" + packagePath; + } + + // locate web script package + WebScriptPath path = getWebScriptRegistry().getPackage(packagePath); + if (path == null) + { + throw new WebScriptException("Web Script Package '" + packagePath + "' not found"); + } + + Map model = new HashMap(7, 1.0f); + model.put("package", path); + return model; + } + +} diff --git a/source/java/org/alfresco/web/scripts/bean/IndexURI.java b/source/java/org/alfresco/web/scripts/bean/IndexURI.java new file mode 100644 index 0000000000..4a57f9593b --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/IndexURI.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.bean; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptPath; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; + + +/** + * Index of a Web Script URI + * + * @author davidc + */ +public class IndexURI extends DeclarativeWebScript +{ + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + // extract web script package + String uriPath = req.getExtensionPath(); + if (uriPath == null || uriPath.length() == 0) + { + uriPath = "/"; + } + if (!uriPath.startsWith("/")) + { + uriPath = "/" + uriPath; + } + + // locate web script package + WebScriptPath path = getWebScriptRegistry().getUri(uriPath); + if (path == null) + { + throw new WebScriptException("Web Script URI '" + uriPath + "' not found"); + } + + Map model = new HashMap(7, 1.0f); + model.put("uri", path); + return model; + } + +} diff --git a/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java b/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java new file mode 100644 index 0000000000..f64f1880be --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/IndexUpdate.java @@ -0,0 +1,90 @@ +/* + * 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.bean; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; +import org.alfresco.web.scripts.facebook.FacebookService; + + +/** + * Retrieves the list of available Web Scripts + * + * @author davidc + */ +public class IndexUpdate extends DeclarativeWebScript +{ + // component dependencies + private FacebookService facebookService; + + /** + * @param facebookService facebook service + */ + public void setFacebookService(FacebookService facebookService) + { + this.facebookService = facebookService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + List tasks = new ArrayList(); + + // reset index + String reset = req.getParameter("reset"); + if (reset != null && reset.equals("on")) + { + // reset list of web scripts + int previousCount = getWebScriptRegistry().getWebScripts().size(); + getWebScriptRegistry().reset(); + tasks.add("Reset Web Scripts Registry; found " + getWebScriptRegistry().getWebScripts().size() + " Web Scripts. Previously, there were " + previousCount + "."); + + // reset facebook service + // TODO: Determine more appropriate place to put this + int appCount = facebookService.getAppModels().size(); + if (appCount > 0) + { + facebookService.reset(); + tasks.add("Reset " + appCount + " Facebook Applications."); + } + } + + // create model for rendering + Map model = new HashMap(7, 1.0f); + model.put("tasks", tasks); + model.put("webscripts", getWebScriptRegistry().getWebScripts()); + return model; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java b/source/java/org/alfresco/web/scripts/bean/JavascriptDebugger.java similarity index 95% rename from source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java rename to source/java/org/alfresco/web/scripts/bean/JavascriptDebugger.java index 3aaa395bdd..1d57ac000b 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebugger.java +++ b/source/java/org/alfresco/web/scripts/bean/JavascriptDebugger.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.Map; @@ -30,7 +30,7 @@ import java.util.Map; import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.WebScriptRequest; -import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptStatus; /** @@ -56,7 +56,7 @@ public class JavascriptDebugger extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { // construct model Map model = new HashMap(7, 1.0f); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java b/source/java/org/alfresco/web/scripts/bean/JavascriptDebuggerPost.java similarity index 95% rename from source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java rename to source/java/org/alfresco/web/scripts/bean/JavascriptDebuggerPost.java index 21c0a927d1..86b2f7be75 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/JavascriptDebuggerPost.java +++ b/source/java/org/alfresco/web/scripts/bean/JavascriptDebuggerPost.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.Map; @@ -30,7 +30,7 @@ import java.util.Map; import org.alfresco.repo.jscript.AlfrescoRhinoScriptDebugger; import org.alfresco.web.scripts.DeclarativeWebScript; import org.alfresco.web.scripts.WebScriptRequest; -import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptStatus; /** @@ -56,7 +56,7 @@ public class JavascriptDebuggerPost extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { String visibleStr = req.getParameter("visible"); boolean visible = Boolean.valueOf(visibleStr); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java b/source/java/org/alfresco/web/scripts/bean/KeywordSearch.java similarity index 88% rename from source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java rename to source/java/org/alfresco/web/scripts/bean/KeywordSearch.java index 77f4e67295..14ea112511 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/KeywordSearch.java +++ b/source/java/org/alfresco/web/scripts/bean/KeywordSearch.java @@ -22,12 +22,10 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.io.StringWriter; -import java.io.UnsupportedEncodingException; import java.io.Writer; -import java.net.URLEncoder; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; @@ -35,23 +33,20 @@ import java.util.Map; import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.template.TemplateNode; -import org.alfresco.repo.web.scripts.RepositoryImageResolver; -import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.TemplateException; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.util.GUID; import org.alfresco.util.ParameterCheck; +import org.alfresco.util.URLEncoder; import org.alfresco.web.scripts.DeclarativeWebScript; -import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.StringUtils; /** @@ -71,8 +66,6 @@ public class KeywordSearch extends DeclarativeWebScript protected static final String QUERY_FORMAT = "query_"; // dependencies - protected ServiceRegistry serviceRegistry; - protected RepositoryImageResolver imageResolver; protected SearchService searchService; /** @@ -83,27 +76,11 @@ public class KeywordSearch extends DeclarativeWebScript this.searchService = searchService; } - /** - * @param imageResolver - */ - public void setRepositoryImageResolver(RepositoryImageResolver imageResolver) - { - this.imageResolver = imageResolver; - } - - /** - * @param serviceRegistry - */ - public void setServiceRegistry(ServiceRegistry serviceRegistry) - { - this.serviceRegistry = serviceRegistry; - } - /* (non-Javadoc) * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { // // process arguments @@ -389,7 +366,7 @@ public class KeywordSearch extends DeclarativeWebScript */ public SearchTemplateNode(NodeRef nodeRef, float score) { - super(nodeRef, serviceRegistry, KeywordSearch.this.imageResolver.getImageResolver()); + super(nodeRef, getServiceRegistry(), getWebScriptRegistry().getTemplateImageResolver()); this.score = score; } @@ -409,19 +386,11 @@ public class KeywordSearch extends DeclarativeWebScript @Override public String getUrl() { - try - { - return MessageFormat.format(URL, new Object[] { - getNodeRef().getStoreRef().getProtocol(), - getNodeRef().getStoreRef().getIdentifier(), - getNodeRef().getId(), - StringUtils.replace(URLEncoder.encode(getName(), "UTF-8"), "+", "%20") } ); - } - catch (UnsupportedEncodingException err) - { - throw new TemplateException("Failed to encode content URL for node: " + getNodeRef(), err); - } + return MessageFormat.format(URL, new Object[] { + getNodeRef().getStoreRef().getProtocol(), + getNodeRef().getStoreRef().getIdentifier(), + getNodeRef().getId(), + URLEncoder.encode(getName()) } ); } } - } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/web/scripts/bean/Login.java b/source/java/org/alfresco/web/scripts/bean/Login.java similarity index 96% rename from source/java/org/alfresco/repo/web/scripts/bean/Login.java rename to source/java/org/alfresco/web/scripts/bean/Login.java index 3bf64e03ca..83ba1f60db 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/Login.java +++ b/source/java/org/alfresco/web/scripts/bean/Login.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.Map; @@ -32,9 +32,9 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.web.scripts.DeclarativeWebScript; -import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; /** @@ -60,7 +60,7 @@ public class Login extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { // extract username and password String username = req.getParameter("u"); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java b/source/java/org/alfresco/web/scripts/bean/LoginTicket.java similarity index 96% rename from source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java rename to source/java/org/alfresco/web/scripts/bean/LoginTicket.java index 3104bc51ed..ba42d372d3 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicket.java +++ b/source/java/org/alfresco/web/scripts/bean/LoginTicket.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.Map; @@ -33,9 +33,9 @@ import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.TicketComponent; import org.alfresco.web.scripts.DeclarativeWebScript; -import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; /** @@ -61,7 +61,7 @@ public class LoginTicket extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { // retrieve ticket from request and current ticket String ticket = req.getExtensionPath(); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java b/source/java/org/alfresco/web/scripts/bean/LoginTicketDelete.java similarity index 97% rename from source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java rename to source/java/org/alfresco/web/scripts/bean/LoginTicketDelete.java index 503dd6e854..9639c8a072 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/LoginTicketDelete.java +++ b/source/java/org/alfresco/web/scripts/bean/LoginTicketDelete.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.Map; @@ -34,9 +34,9 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.TicketComponent; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.web.scripts.DeclarativeWebScript; -import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptException; import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; /** @@ -71,7 +71,7 @@ public class LoginTicketDelete extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { // retrieve ticket from request and current ticket String ticket = req.getExtensionPath(); diff --git a/source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java b/source/java/org/alfresco/web/scripts/bean/SearchEngines.java similarity index 98% rename from source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java rename to source/java/org/alfresco/web/scripts/bean/SearchEngines.java index ad2e2f847e..7ef0ddc8c7 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/SearchEngines.java +++ b/source/java/org/alfresco/web/scripts/bean/SearchEngines.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.util.HashMap; import java.util.HashSet; @@ -35,8 +35,8 @@ import org.alfresco.i18n.I18NUtil; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.web.config.OpenSearchConfigElement; import org.alfresco.web.scripts.DeclarativeWebScript; -import org.alfresco.web.scripts.Status; import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -80,7 +80,7 @@ public class SearchEngines extends DeclarativeWebScript * @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */ @Override - protected Map executeImpl(WebScriptRequest req, Status status) + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) { String urlType = req.getParameter("type"); if (urlType == null || urlType.length() == 0) diff --git a/source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java b/source/java/org/alfresco/web/scripts/bean/SearchProxy.java similarity index 99% rename from source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java rename to source/java/org/alfresco/web/scripts/bean/SearchProxy.java index ba1e3decb0..2889ab91a2 100644 --- a/source/java/org/alfresco/repo/web/scripts/bean/SearchProxy.java +++ b/source/java/org/alfresco/web/scripts/bean/SearchProxy.java @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.web.scripts.bean; +package org.alfresco.web.scripts.bean; import java.io.IOException; import java.io.InputStream; @@ -47,7 +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.servlet.WebScriptServletResponse; +import org.alfresco.web.scripts.WebScriptServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Attribute; diff --git a/source/java/org/alfresco/web/scripts/bean/ServiceDescription.java b/source/java/org/alfresco/web/scripts/bean/ServiceDescription.java new file mode 100644 index 0000000000..953b135490 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/ServiceDescription.java @@ -0,0 +1,97 @@ +/* + * 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.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptDescription; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; + + +/** + * Retrieves a Web Script Description Document + * + * @author davidc + */ +public class ServiceDescription extends AbstractWebScript +{ + + public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException + { + // extract web script id + String scriptId = req.getExtensionPath(); + if (scriptId == null || scriptId.length() == 0) + { + throw new WebScriptException("Web Script Id not provided"); + } + + // locate web script + WebScript script = getWebScriptRegistry().getWebScript(scriptId); + if (script == null) + { + throw new WebScriptException("Web Script Id '" + scriptId + "' not found"); + } + + // retrieve description document + WebScriptDescription desc = script.getDescription(); + InputStream serviceDescIS = null; + try + { + serviceDescIS = desc.getDescDocument(); + OutputStream out = res.getOutputStream(); + res.setContentType(MimetypeMap.MIMETYPE_XML + ";charset=UTF-8"); + byte[] buffer = new byte[2048]; + int read = serviceDescIS.read(buffer); + while (read != -1) + { + out.write(buffer, 0, read); + read = serviceDescIS.read(buffer); + } + } + catch(IOException e) + { + throw new WebScriptException("Failed to read Web Script description document for '" + scriptId + "'", e); + } + finally + { + try + { + if (serviceDescIS != null) serviceDescIS.close(); + } + catch(IOException e) + { + // NOTE: ignore close exception + } + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/bean/ServiceDump.java b/source/java/org/alfresco/web/scripts/bean/ServiceDump.java new file mode 100644 index 0000000000..f5cc5dd847 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/ServiceDump.java @@ -0,0 +1,192 @@ +/* + * 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.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptStatus; +import org.alfresco.web.scripts.WebScriptStorage; +import org.alfresco.web.scripts.WebScriptStore; + + +/** + * Dumps everything known about the specified Web Script + * + * @author davidc + */ +public class ServiceDump extends DeclarativeWebScript +{ + private WebScriptStorage storage; + + + public void setStorage(WebScriptStorage storage) + { + this.storage = storage; + } + + + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + // extract web script id + String scriptId = req.getExtensionPath(); + if (scriptId == null || scriptId.length() == 0) + { + throw new WebScriptException("Web Script Id not provided"); + } + + // locate web script + WebScript script = getWebScriptRegistry().getWebScript(scriptId); + if (script == null) + { + throw new WebScriptException("Web Script Id '" + scriptId + "' not found"); + } + + // construct model + Map model = new HashMap(7, 1.0f); + Map implPaths = new HashMap(); + List modelStores = new ArrayList(); + model.put("script", script.getDescription()); + model.put("script_class", script.getClass().toString()); + model.put("stores", modelStores); + + // locate web script stores + Collection stores = storage.getStores(); + for (WebScriptStore store : stores) + { + Store modelStore = new Store(); + modelStore.path = store.getBasePath(); + + // locate script implementation files + String[] scriptPaths = store.getScriptDocumentPaths(script); + for (String scriptPath : scriptPaths) + { + Implementation impl = new Implementation(); + impl.path = scriptPath; + impl.overridden = implPaths.containsKey(scriptPath); + + // extract implementation content + InputStream documentIS = null; + try + { + documentIS = store.getDocument(scriptPath); + InputStreamReader isReader = new InputStreamReader(documentIS); + StringWriter stringWriter = new StringWriter(); + char[] buffer = new char[2048]; + int read = isReader.read(buffer); + while (read != -1) + { + stringWriter.write(buffer, 0, read); + read = isReader.read(buffer); + } + impl.content = stringWriter.toString(); + } + catch(IOException e) + { + impl.throwable = e; + } + finally + { + try + { + if (documentIS != null) documentIS.close(); + } + catch(IOException e) + { + // NOTE: ignore close exception + } + } + + // record web script implementation file against store + modelStore.files.add(impl); + } + + // record store in list of stores + modelStores.add(modelStore); + } + + return model; + } + + + public static class Store + { + private String path; + private Collection files = new ArrayList(); + + public String getPath() + { + return path; + } + + public Collection getFiles() + { + return files; + } + + } + + public static class Implementation + { + private String path; + private boolean overridden; + private String content; + private Exception throwable; + + public String getPath() + { + return path; + } + + public String getContent() + { + return content; + } + + public boolean getOverridden() + { + return overridden; + } + + public Throwable getException() + { + return throwable; + } + } + +} + \ No newline at end of file diff --git a/source/java/org/alfresco/web/scripts/bean/ServiceInstall.java b/source/java/org/alfresco/web/scripts/bean/ServiceInstall.java new file mode 100644 index 0000000000..4f3fc2c0bc --- /dev/null +++ b/source/java/org/alfresco/web/scripts/bean/ServiceInstall.java @@ -0,0 +1,245 @@ +/* + * 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.bean; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.DeclarativeWebScript; +import org.alfresco.web.scripts.WebScript; +import org.alfresco.web.scripts.WebScriptDescription; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptStatus; +import org.alfresco.web.scripts.WebScriptStorage; +import org.alfresco.web.scripts.WebScriptStore; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.XPath; +import org.dom4j.io.SAXReader; + + +/** + * Install a Web Script + * + * @author davidc + */ +public class ServiceInstall extends DeclarativeWebScript +{ + private WebScriptStorage storage; + + + public void setStorage(WebScriptStorage storage) + { + this.storage = storage; + } + + + @Override + protected Map executeImpl(WebScriptRequest req, WebScriptStatus status) + { + if (!(req instanceof WebScriptServletRequest)) + { + throw new WebScriptException("Web Script install only supported via HTTP Servlet"); + } + HttpServletRequest servletReq = ((WebScriptServletRequest)req).getHttpServletRequest(); + + // construct model + Map model = new HashMap(7, 1.0f); + List installedFiles = new ArrayList(); + model.put("installedFiles", installedFiles); + + try + { + // extract uploaded file + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + boolean isMultipart = upload.isMultipartContent(servletReq); + if (!isMultipart) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script install request is not multi-part"); + } + FileItem part = null; + List files = upload.parseRequest(servletReq); + for (FileItem file : files) + { + if (!file.isFormField()) + { + if (part != null) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Web Script install request expects only one file upload"); + } + part = file; + } + } + + // find web script definition + Document document = null; + InputStream fileIS = part.getInputStream(); + try + { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileIS)); + SAXReader reader = new SAXReader(); + document = reader.read(bufferedReader); + } + finally + { + fileIS.close(); + } + Element rootElement = document.getRootElement(); + XPath xpath = rootElement.createXPath("//ws:webscript"); + Map uris = new HashMap(); + uris.put("ws", "http://www.alfresco.org/webscript/1.0"); + xpath.setNamespaceURIs(uris); + List nodes = xpath.selectNodes(rootElement); + if (nodes.size() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Cannot locate Web Script in uploaded file"); + } + + // extract web script definition + Element webscriptElem = (Element)nodes.get(0); + String scriptId = webscriptElem.attributeValue("scriptid"); + if (scriptId == null || scriptId.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Expected scriptid value on webscript element"); + } + Iterator iter = webscriptElem.elementIterator(); + while (iter.hasNext()) + { + Element fileElem = (Element)iter.next(); + String webscriptStore = fileElem.attributeValue("store"); + if (webscriptStore == null || webscriptStore.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Expected store value on webscript element"); + } + String webscriptPath = fileElem.attributeValue("path"); + if (webscriptPath == null || webscriptPath.length() == 0) + { + throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Expected file value on webscript element"); + } + String webscriptContent = fileElem.getText(); + + // install web script implementation file + installFile(webscriptStore, webscriptPath, webscriptContent); + InstalledFile installedFile = new InstalledFile(); + installedFile.store = webscriptStore; + installedFile.path = webscriptPath; + installedFiles.add(installedFile); + } + + // reset the web script registry + WebScriptRegistry registry = getWebScriptRegistry(); + registry.reset(); + + // locate installed web script + WebScript webscript = registry.getWebScript(scriptId); + if (webscript == null) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to install Web Script " + scriptId); + } + model.put("installedScript", webscript.getDescription()); + } + catch(FileUploadException e) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + catch(DocumentException e) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + catch(IOException e) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + } + + return model; + } + + + private void installFile(String storePath, String file, String content) + { + // retrieve appropriate web script store + WebScriptStore store = storage.getStore(storePath); + if (store == null) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Store path " + storePath + " refers to a store that does not exist"); + } + + // determine if file already exists in store + if (store.hasDocument(file)) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Web Script file " + file + " already exists in store " + storePath); + } + + // create the web script file + try + { + store.createDocument(file, content); + } + catch(IOException e) + { + throw new WebScriptException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to install Web Script file " + file + " into store" + storePath); + } + } + + + public static class InstalledFile + { + private WebScriptDescription script; + private String store; + private String path; + + public String getStore() + { + return store; + } + + public String getPath() + { + return path; + } + } + +} + \ No newline at end of file diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java new file mode 100644 index 0000000000..3c72975c93 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIRuntime.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.alfresco.web.scripts.WebScriptServletRuntime; + + +/** + * Runtime to support requests from Facebook + * + * @author davidc + */ +public class FacebookAPIRuntime extends WebScriptServletRuntime +{ + + /** + * Construct + * + * @param registry + * @param serviceRegistry + * @param authenticator + * @param req + * @param res + */ + public FacebookAPIRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry, WebScriptServletAuthenticator authenticator, + HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig) + { + super(registry, serviceRegistry, authenticator, req, res, serverConfig); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new FacebookServletRequest(serverConfig, req, match, getScriptUrl()); + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java new file mode 100644 index 0000000000..5dc41a26f5 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAPIServlet.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.WebScriptRuntime; +import org.alfresco.web.scripts.WebScriptServlet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Web Script API entry point (with Facebook authentication) + * + * @author davidc + */ +public class FacebookAPIServlet extends WebScriptServlet +{ + private static final long serialVersionUID = 4209892938069597860L; + + // Logger + private static final Log logger = LogFactory.getLog(FacebookAPIServlet.class); + + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing facebook api request (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + + WebScriptRuntime runtime = new FacebookAPIRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig); + runtime.executeScript(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServlet#getDefaultAuthenticator() + */ + @Override + protected String getDefaultAuthenticator() + { + return "facebook.authenticator"; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java new file mode 100644 index 0000000000..e1b9f41872 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAppModel.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + + +/** + * Facebook Application + * + * @author davidc + */ +public class FacebookAppModel +{ + String appId; + String apiKey; + String secretKey; + + /** + * Construct + * + * @param apiKey + */ + public FacebookAppModel(String apiKey) + { + this.apiKey = apiKey; + } + + /** + * @return application apiKey + */ + public String getApiKey() + { + return apiKey; + } + + /** + * @return application secret + */ + public String getSecret() + { + return secretKey; + } + + /** + * @param secretKey application secret + */ + public void setSecret(String secretKey) + { + this.secretKey = secretKey; + } + + /** + * @return application id + */ + public String getId() + { + return appId; + } + + /** + * @param appId application id + */ + public void setId(String appId) + { + this.appId = appId; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java b/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java new file mode 100644 index 0000000000..0fd22c310b --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookAuthenticator.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import java.io.IOException; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.alfresco.web.scripts.WebScriptServletRequest; +import org.alfresco.web.scripts.WebScriptServletResponse; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Web Script Authenticator that supports Facebook authentication + * mechanism. + * + * Upon success, the request is authenticated as the Facebook User Id. + * + * @author davidc + */ +public class FacebookAuthenticator implements WebScriptServletAuthenticator +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookAuthenticator.class); + + // FBML for Facebook login redirect + private static final String LOGIN_REDIRECT = ""; + + + /* (non-Javadoc) + * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) + */ + public boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptServletRequest req, WebScriptServletResponse res) + { + // TODO: Refactor with Web Script F/W Extraction + FacebookServletRequest fbreq = (FacebookServletRequest)req; + + String sessionKey = fbreq.getSessionKey(); + String user = fbreq.getUserId(); + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_session_key = '" + sessionKey + "'"); + logger.debug("fb_sig_user = '" + user + "'"); + } + + if ((sessionKey == null || sessionKey.length() == 0) || (user == null || user.length() == 0)) + { + // session has not been established, redirect to login + + String apiKey = fbreq.getApiKey(); + String canvas = (fbreq.isInCanvas()) ? "&canvas" : ""; + + if (logger.isDebugEnabled()) + { + logger.debug("fb_sig_api_key = '" + apiKey + "'"); + logger.debug("fb_sig_in_canvas = '" + canvas + "'"); + } + + try + { + String redirect = String.format(LOGIN_REDIRECT, apiKey, canvas); + + if (logger.isDebugEnabled()) + logger.debug("Facebook session not established; redirecting via " + redirect); + + res.getWriter().write(redirect); + } + catch (IOException e) + { + throw new WebScriptException("Redirect to login failed", e); + } + return false; + } + + if (logger.isDebugEnabled()) + logger.debug("Facebook session established; authenticating as user " + user); + + // session has been established, authenticate as Facebook user id + AuthenticationUtil.setCurrentUser(user); + return true; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookError.java b/source/java/org/alfresco/web/scripts/facebook/FacebookError.java new file mode 100644 index 0000000000..c03404f436 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookError.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +/** + * Facebook Error. + * + * @author David Caruana + */ +public class FacebookError extends RuntimeException +{ + private static final long serialVersionUID = -7338963365877285084L; + + private int code = -1; + + public FacebookError(String msg) + { + super(msg); + } + + public FacebookError(int code, String msg) + { + super(msg); + this.code = code; + } + + public int getCode() + { + return code; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java new file mode 100644 index 0000000000..e2152a4a0a --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookModel.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import com.facebook.api.FacebookException; +import com.facebook.api.FacebookRestClient; + + +/** + * Facebook Javascript API + * + * @author davidc + */ +public class FacebookModel +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookModel.class); + + private FacebookServletRequest req; + private FacebookRestClient client; + private String[] friends; + private String[] appFriends; + + + /** + * Construct + * + * @param req + */ + public FacebookModel(FacebookServletRequest req) + { + this.req = req; + } + + /** + * @return the facebook rest client + */ + private FacebookRestClient getClient() + { + if (client == null) + { + String apiKey = req.getApiKey(); + String secretKey = req.getSecretKey(); + String sessionKey = req.getSessionKey(); + if (sessionKey == null) + { + client = new FacebookRestClient(apiKey, secretKey); + } + else + { + client = new FacebookRestClient(apiKey, secretKey, sessionKey); + } + + if (logger.isDebugEnabled()) + client.setDebug(true); + } + return client; + } + + /** + * @return all friends of the logged in facebook user + */ + public String[] getFriends() + { + if (friends == null) + { + friends = req.getFriends(); + if (friends == null) + { + try + { + Document response = getClient().friends_get(); + NodeList uids = response.getElementsByTagName("uid"); + String[] uidsArray = new String[uids.getLength()]; + for (int i = 0; i < uids.getLength(); i++) + { + uidsArray[i] = uids.item(i).getTextContent(); + } + friends = uidsArray; + } + catch(FacebookException e) + { + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch(IOException e) + { + throw new FacebookError(e.getMessage()); + } + } + } + return friends; + } + + /** + * @return friends who are users of the current application + */ + public String[] getAppFriends() + { + if (appFriends == null) + { + try + { + Document response = getClient().friends_getAppUsers(); + NodeList uids = response.getElementsByTagName("uid"); + String[] uidsArray = new String[uids.getLength()]; + for (int i = 0; i < uids.getLength(); i++) + { + uidsArray[i] = uids.item(i).getTextContent(); + } + appFriends = uidsArray; + } + catch(FacebookException e) + { + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch(IOException e) + { + throw new FacebookError(e.getMessage()); + } + } + return appFriends; + } + + /** + * Post User Action + * + * For details see: + * http://wiki.developers.facebook.com/index.php/Feed.publishActionOfUser + * + * @param title + * @param body + * @return + */ + public int postUserAction(String title, String body) + { + try + { + Document response = getClient().feed_publishActionOfUser(title, body); + int status = Integer.parseInt(response.getDocumentElement().getTextContent()); + return status; + } + catch (FacebookException e) + { + if (logger.isErrorEnabled()) + logger.error("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); + throw new FacebookError(e.getCode(), e.getMessage()); + } + catch (IOException e) + { + if (logger.isErrorEnabled()) + logger.error("Failed to post user action [title=" + title + ", body=" + body + "] due to " + e.toString()); + throw new FacebookError(e.getMessage()); + } + } + + /** + * @return user id of logged in facebook user + */ + public String getUser() + { + return req.getUserId(); + } + + /** + * @return application id of current application + */ + public String getAppId() + { + return req.getAppId(); + } + + /** + * @return session key of current facebook session + */ + public String getSessionKey() + { + return req.getSessionKey(); + } + + /** + * @return application api key + */ + public String getApiKey() + { + return req.getApiKey(); + } + + /** + * @return application secret key + */ + public String getSecret() + { + return req.getSecretKey(); + } + + /** + * @return facebook canvas path (as entered into 'Create Application' dialog) + */ + public String getCanvasPath() + { + return req.getCanvasPath(); + } + + /** + * @return facebook canvas url (http://apps.facebook.com/canvasPath) + */ + public String getCanvasURL() + { + return "http://apps.facebook.com/" + getCanvasPath(); + } + + /** + * @return facebook page url (http://apps.facebook.com/canvasPath/page) + */ + public String getPageURL() + { + return "http://apps.facebook.com" + req.getPagePath(); + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookService.java b/source/java/org/alfresco/web/scripts/facebook/FacebookService.java new file mode 100644 index 0000000000..895f7b3b48 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookService.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.alfresco.service.cmr.repository.ScriptLocation; +import org.alfresco.web.scripts.WebScriptContext; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Facebook Service + * + * @author davidc + */ +public class FacebookService +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookService.class); + + // Facebook Application Cache + private Map apps = new HashMap(); + private ReentrantReadWriteLock appsLock = new ReentrantReadWriteLock(); + + // Component dependencies + private WebScriptRegistry registry; + private WebScriptContext context; + + + /** + * @param registry Web Script Registry + */ + public void setRegistry(WebScriptRegistry registry) + { + this.registry = registry; + } + + /** + * Gets the application model for the given application api key + * + * @param apiKey api key + * @return application model + */ + FacebookAppModel getAppModel(String apiKey) + { + FacebookAppModel facebookApp = null; + appsLock.readLock().lock(); + + try + { + facebookApp = apps.get(apiKey); + if (facebookApp == null) + { + // Upgrade read lock to write lock + appsLock.readLock().unlock(); + appsLock.writeLock().lock(); + + try + { + // Check again + facebookApp = apps.get(apiKey); + if (facebookApp == null) + { + if (logger.isDebugEnabled()) + logger.debug("Initialising Facebook Application '" + apiKey + "'"); + + // Locate app initialisation script in web script store + String appPath = "com/facebook/_apps/app." + apiKey + ".js"; + ScriptLocation appScript = registry.getScriptProcessor().findScript(appPath); + if (appScript == null) + { + throw new WebScriptException("Unable to locate application initialisation script '" + appPath + "'"); + } + + // Execute app initialisation script + Map model = new HashMap(); + FacebookAppModel app = new FacebookAppModel(apiKey); + model.put("app", app); + registry.getScriptProcessor().executeScript(appScript, model); + + // Validate initialisation + if (app.getSecret() == null) + { + throw new WebScriptException("Secret key for application '" + apiKey + "' has not been specified."); + } + if (app.getApiKey() == null) + { + throw new WebScriptException("Application Id for application '" + apiKey + "' has not been specified."); + } + + apps.put(apiKey, app); + facebookApp = app; + } + } + finally + { + // Downgrade lock to read + appsLock.readLock().lock(); + appsLock.writeLock().unlock(); + } + } + return facebookApp; + } + finally + { + appsLock.readLock().unlock(); + } + } + + /** + * Gets currently known Facebook Applications + * + * @return map (name, application) of known applications + */ + public Map getAppModels() + { + return apps; + } + + /** + * Reset Facebook Service + */ + public void reset() + { + appsLock.writeLock().lock(); + try + { + apps.clear(); + } + finally + { + appsLock.writeLock().unlock(); + } + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java new file mode 100644 index 0000000000..20bf71a2d8 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServlet.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.web.scripts.WebScriptRuntime; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; + + +/** + * Facebook Canvas Page Requests + * + * @author davidc + */ +public class FacebookServlet extends FacebookAPIServlet +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookServlet.class); + + // Component Dependencies + protected FacebookService facebookService; + + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException + { + if (logger.isDebugEnabled()) + logger.debug("Processing facebook canvas (" + req.getMethod() + ") " + req.getRequestURL() + (req.getQueryString() != null ? "?" + req.getQueryString() : "")); + + WebScriptRuntime runtime = new FacebookServletRuntime(registry, serviceRegistry, authenticator, req, res, serverConfig, facebookService); + runtime.executeScript(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServlet#initServlet(org.springframework.context.ApplicationContext) + */ + @Override + protected void initServlet(ApplicationContext context) + { + facebookService = (FacebookService)context.getBean("facebook.service"); + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java new file mode 100644 index 0000000000..afce511a14 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRequest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptException; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptServletRequest; + + +/** + * Facebook Servlet Request + * + * @author davidc + */ +public class FacebookServletRequest extends WebScriptServletRequest +{ + private String appId; + private String secretKey; + private String pathInfo; + + + /** + * Construct + * + * @param serverConfig + * @param req + * @param serviceMatch + */ + public FacebookServletRequest(ServerConfigElement serverConfig, HttpServletRequest req, WebScriptMatch serviceMatch, String pathInfo) + { + super(serverConfig, req, serviceMatch); + this.pathInfo = pathInfo; + } + + /** + * @param secretKey application secret + */ + /*package*/ void setSecretKey(String secretKey) + { + this.secretKey = secretKey; + } + + /** + * @param appId application id + */ + /*package*/ void setAppId(String appId) + { + this.appId = appId; + } + + /** + * @return application api key + */ + public String getApiKey() + { + return getParameter("fb_sig_api_key"); + } + + /** + * @return Facebook user id + */ + public String getUserId() + { + return getParameter("fb_sig_user"); + } + + /** + * @return session key + */ + public String getSessionKey() + { + return getParameter("fb_sig_session_key"); + } + + /** + * @return true => within Facebook canvas + */ + public boolean isInCanvas() + { + String canvas = getParameter("fb_sig_api_key"); + return (canvas == null || canvas.equals("1")); + } + + /** + * @return application secret + */ + public String getSecretKey() + { + return secretKey; + } + + /** + * @return application id + */ + public String getAppId() + { + return appId; + } + + /** + * @return application canvas path + */ + public String getCanvasPath() + { + String pathInfo = getPathInfo(); + String[] pathSegments = pathInfo.split("/"); + if (pathSegments.length < 3) + { + throw new WebScriptException("Cannot establish Facebook Canvas Page URL from request " + getURL()); + } + return pathSegments[2]; + } + + /** + * @return application page path + */ + public String getPagePath() + { + String pagePath = getPathInfo(); + if (pagePath.startsWith("/facebook")) + { + pagePath = pathInfo.substring("/facebook".length()); + } + return pagePath; + } + + /** + * @return friends of authenticated Facebook user + */ + public String[] getFriends() + { + String[] friends; + String friendsStr = getParameter("fb_sig_friends"); + friends = (friendsStr == null) ? new String[0] : friendsStr.split(","); + return friends; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServletRequest#getPathInfo() + */ + @Override + public String getPathInfo() + { + return pathInfo; + } + +} diff --git a/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java new file mode 100644 index 0000000000..a7a8965a16 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/facebook/FacebookServletRuntime.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.scripts.facebook; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.web.config.ServerConfigElement; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptServletAuthenticator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Facebook Canvas Page Servlet. + * + * @author davidc + */ +public class FacebookServletRuntime extends FacebookAPIRuntime +{ + // Logger + private static final Log logger = LogFactory.getLog(FacebookServletRuntime.class); + + // Component dependencies + protected FacebookService facebookService; + + /** + * Construct + * + * @param registry + * @param serviceRegistry + * @param authenticator + * @param req + * @param res + */ + public FacebookServletRuntime(WebScriptRegistry registry, ServiceRegistry serviceRegistry, WebScriptServletAuthenticator authenticator, + HttpServletRequest req, HttpServletResponse res, ServerConfigElement serverConfig, FacebookService facebookService) + { + super(registry, serviceRegistry, authenticator, req, res, serverConfig); + this.facebookService = facebookService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + FacebookServletRequest fbreq = new FacebookServletRequest(serverConfig, req, match, getScriptUrl()); + + if (match != null) + { + FacebookAppModel appModel = facebookService.getAppModel(fbreq.getApiKey()); + fbreq.setSecretKey(appModel.getSecret()); + fbreq.setAppId(appModel.getId()); + } + + if (logger.isDebugEnabled()) + logger.debug("Facebook request [apiKey=" + fbreq.getApiKey() + ", user=" + fbreq.getUserId() + ", session=" + fbreq.getSessionKey() + ", secret=" + fbreq.getSecretKey() + "]"); + + return fbreq; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptServletRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + return "/facebook" + super.getScriptUrl(); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getStatusCodeTemplate(int) + */ + @Override + protected String getStatusCodeTemplate(int statusCode) + { + return "/fbml." + statusCode + ".ftl"; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRuntime#getStatusTemplate() + */ + @Override + protected String getStatusTemplate() + { + return "/fbml.status.ftl"; + } + +} diff --git a/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java b/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java new file mode 100644 index 0000000000..9bccb02316 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/jsf/UIWebScript.java @@ -0,0 +1,334 @@ +/* + * 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.jsf; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Map; + +import javax.faces.component.UIComponent; +import javax.faces.context.FacesContext; +import javax.faces.el.ValueBinding; +import javax.faces.event.AbortProcessingException; +import javax.faces.event.ActionEvent; +import javax.faces.event.FacesEvent; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.web.scripts.DeclarativeWebScriptRegistry; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptRegistry; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.WebScriptRuntime; +import org.alfresco.web.scripts.WebScriptURLRequest; +import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication; +import org.alfresco.web.ui.common.component.SelfRenderingComponent; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.jsf.FacesContextUtils; + +/** + * JSF Component implementation for the WebScript component. + *

+ * Responsible for generating a JSF Component specific WebScriptRuntime instance and + * executing the specified WebScript against the runtime. + * + * @author Kevin Roast + */ +public class UIWebScript extends SelfRenderingComponent +{ + private static Log logger = LogFactory.getLog(UIWebScript.class); + + /** WebScript URL to execute */ + private String scriptUrl = null; + + /** User defined script context value */ + private Object context = null; + + private boolean scriptUrlModified = false; + + private WebScriptRegistry registry; + private ServiceRegistry serviceRegistry;; + + /** + * Default constructor + */ + public UIWebScript() + { + WebApplicationContext ctx = FacesContextUtils.getRequiredWebApplicationContext( + FacesContext.getCurrentInstance()); + this.registry = (DeclarativeWebScriptRegistry)ctx.getBean("webscripts.registry"); + this.serviceRegistry = (ServiceRegistry)ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + } + + /** + * @see javax.faces.component.UIComponent#getFamily() + */ + @Override + public String getFamily() + { + return "org.alfresco.faces.Controls"; + } + + /** + * @see javax.faces.component.StateHolder#restoreState(javax.faces.context.FacesContext, java.lang.Object) + */ + public void restoreState(FacesContext context, Object state) + { + Object values[] = (Object[])state; + // standard component attributes are restored by the super class + super.restoreState(context, values[0]); + this.scriptUrl = (String)values[1]; + this.scriptUrlModified = (Boolean)values[2]; + this.context = values[3]; + } + + /** + * @see javax.faces.component.StateHolder#saveState(javax.faces.context.FacesContext) + */ + public Object saveState(FacesContext context) + { + Object values[] = new Object[] { + super.saveState(context), this.scriptUrl, this.scriptUrlModified, this.context}; + return values; + } + + /* (non-Javadoc) + * @see javax.faces.component.UIComponentBase#broadcast(javax.faces.event.FacesEvent) + */ + @Override + public void broadcast(FacesEvent event) throws AbortProcessingException + { + if (event instanceof WebScriptEvent) + { + this.scriptUrlModified = true; + this.scriptUrl = ((WebScriptEvent)event).Url; + } + else + { + super.broadcast(event); + } + } + + /* (non-Javadoc) + * @see javax.faces.component.UIComponentBase#decode(javax.faces.context.FacesContext) + */ + @Override + public void decode(FacesContext context) + { + Map requestMap = context.getExternalContext().getRequestParameterMap(); + String fieldId = this.getClientId(context); + String value = (String)requestMap.get(fieldId); + if (value != null && value.length() != 0) + { + // found web-script URL for this component + try + { + String url = URLDecoder.decode(value, "UTF-8"); + queueEvent(new WebScriptEvent(this, url)); + } + catch (UnsupportedEncodingException e) + { + throw new AlfrescoRuntimeException("Unable to decode utf-8 script url."); + } + } + } + + /** + * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext) + */ + @Override + public void encodeBegin(FacesContext context) throws IOException + { + String scriptUrl = getScriptUrl(); + + Object scriptContext = getContext(); + if (scriptContext != null) + { + // context object supplied, perform simple variable substitution + if (scriptContext instanceof Map) + { + Map scriptContextMap = (Map)scriptContext; + for (String key : scriptContextMap.keySet()) + { + scriptUrl = scriptUrl.replace(key, scriptContextMap.get(key).toString()); + } + } + else + { + // currently we only support {noderef} replacement directly + // TODO: move the variable substitution into the WebScript engine - pass in + // a bag of context objects i.e. name/value pairs of well known keys + // allow common values such as noderef, nodeid, path, user etc. + scriptUrl = scriptUrl.replace("{noderef}", scriptContext.toString()); + } + } + + // execute WebScript + if (logger.isDebugEnabled()) + logger.debug("Processing UIWebScript encodeBegin(): " + scriptUrl); + + WebScriptRuntime runtime = new WebScriptJSFRuntime(context, scriptUrl); + runtime.executeScript(); + } + + /** + * Set the scriptUrl + * + * @param scriptUrl the scriptUrl + */ + public void setScriptUrl(String scriptUrl) + { + this.scriptUrl = getFacesContext().getExternalContext().getRequestContextPath() + scriptUrl; + } + + /** + * @return the scriptUrl + */ + public String getScriptUrl() + { + if (this.scriptUrlModified == false) + { + ValueBinding vb = getValueBinding("scriptUrl"); + if (vb != null) + { + this.scriptUrl = getFacesContext().getExternalContext().getRequestContextPath() + + (String)vb.getValue(getFacesContext()); + } + } + return this.scriptUrl; + } + + /** + * @return the user defined script context object + */ + public Object getContext() + { + ValueBinding vb = getValueBinding("context"); + if (vb != null) + { + this.context = vb.getValue(getFacesContext()); + } + return this.context; + } + + /** + * @param context the user defined script context to set + */ + public void setContext(Object context) + { + this.context = context; + } + + + // ------------------------------------------------------------------------------ + // Inner classes + + /** + * Class representing the clicking of a webscript url action. + */ + public static class WebScriptEvent extends ActionEvent + { + public WebScriptEvent(UIComponent component, String url) + { + super(component); + this.Url = url; + } + + public String Url = null; + } + + /** + * Implementation of a WebScriptRuntime for the JSF environment + * + * @author Kevin Roast + */ + private class WebScriptJSFRuntime extends WebScriptRuntime + { + private FacesContext fc; + private String scriptUrl; + private String script; + + WebScriptJSFRuntime(FacesContext fc, String scriptUrl) + { + super(registry, serviceRegistry); + this.fc = fc; + this.scriptUrl = scriptUrl; + this.script = WebScriptURLRequest.splitURL(scriptUrl)[2]; + } + + /** + * @see org.alfresco.web.scripts.WebScriptRuntime#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean) + */ + @Override + protected boolean authenticate(RequiredAuthentication required, boolean isGuest, WebScriptRequest req, WebScriptResponse res) + { + // JSF component already in an authenticated environment as the + // /faces servlet filter (or JSF portlet wrapper) is called first + return true; + } + + /** + * @see org.alfresco.web.scripts.WebScriptRuntime#createRequest(org.alfresco.web.scripts.WebScriptMatch) + */ + @Override + protected WebScriptRequest createRequest(WebScriptMatch match) + { + return new WebScriptJSFRequest(this.scriptUrl, match); + } + + /** + * @see org.alfresco.web.scripts.WebScriptRuntime#createResponse() + */ + @Override + protected WebScriptResponse createResponse() + { + return new WebScriptJSFResponse(fc, UIWebScript.this); + } + + /** + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptMethod() + */ + @Override + protected String getScriptMethod() + { + return "GET"; + } + + /** + * @see org.alfresco.web.scripts.WebScriptRuntime#getScriptUrl() + */ + @Override + protected String getScriptUrl() + { + return this.script; + } + } +} diff --git a/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java new file mode 100644 index 0000000000..285a3449bc --- /dev/null +++ b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java @@ -0,0 +1,111 @@ +/* + * 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.jsf; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.web.scripts.WebScriptMatch; +import org.alfresco.web.scripts.WebScriptURLRequest; + +/** + * Implementation of a WebScript Request for the JSF environment. + * + * @author Kevin Roast + */ +public class WebScriptJSFRequest extends WebScriptURLRequest +{ + /** + * Constructor + * + * @param fc FacesContext + * @param match WebScriptMatch that matched this webscript + * @param scriptUrl The script URL this request is for + */ + public WebScriptJSFRequest(String scriptUrl, WebScriptMatch match) + { + this(splitURL(scriptUrl), match); + } + + public WebScriptJSFRequest(String[] scriptUrlParts, WebScriptMatch match) + { + super(scriptUrlParts, match); + // decode url args (as they would be if this was a servlet) + try + { + for (String name : this.queryArgs.keySet()) + { + this.queryArgs.put(name, URLDecoder.decode(this.queryArgs.get(name), "UTF-8")); + } + } + catch (UnsupportedEncodingException e) + { + throw new AlfrescoRuntimeException("Unable to decode UTF-8 url!", e); + } + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getServerPath() + */ + public String getServerPath() + { + // NOTE: not accessable from JSF context - cannot create absolute external urls... + return ""; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAgent() + */ + public String getAgent() + { + // NOTE: unknown in the JSF environment + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return new String[0]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return new String[0]; + } +} diff --git a/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFResponse.java b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFResponse.java new file mode 100644 index 0000000000..4e5c37720f --- /dev/null +++ b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFResponse.java @@ -0,0 +1,177 @@ +/* + * 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.jsf; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import javax.faces.component.UIForm; +import javax.faces.context.FacesContext; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.util.URLEncoder; +import org.alfresco.web.scripts.WebScriptCache; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.ui.common.Utils; +import org.apache.myfaces.shared_impl.renderkit.html.HtmlFormRendererBase; + +/** + * Implementation of a WebScript Response for the JSF environment. + * + * @author Kevin Roast + */ +public class WebScriptJSFResponse implements WebScriptResponse +{ + private FacesContext fc; + private UIWebScript component; + + WebScriptJSFResponse(FacesContext fc, UIWebScript component) + { + this.fc = fc; + this.component = component; + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#encodeScriptUrl(java.lang.String) + */ + public String encodeScriptUrl(String url) + { + UIForm form = Utils.getParentForm(fc, component); + if (form == null) + { + throw new IllegalStateException("Must nest components inside UIForm to generate form submit!"); + } + + String fieldId = component.getClientId(fc); + String formClientId = form.getClientId(fc); + + StringBuilder buf = new StringBuilder(256); + // dirty - but can't see any other way to convert to a JSF action click... + buf.append("#\" onclick=\""); + buf.append("document.forms["); + buf.append("'"); + buf.append(formClientId); + buf.append("'"); + buf.append("]['"); + buf.append(fieldId); + buf.append("'].value="); + buf.append("'"); + // encode the URL to the webscript + buf.append(URLEncoder.encode(url)); + buf.append("'"); + buf.append(";"); + + buf.append("document.forms["); + buf.append("'"); + buf.append(formClientId); + buf.append("'"); + buf.append("].submit();"); + + buf.append("return false;"); + + // weak, but this seems to be the way Sun RI/MyFaces do it... + HtmlFormRendererBase.addHiddenCommandParameter(fc, form, fieldId); + + return buf.toString(); + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#reset() + */ + public void reset() + { + // nothing to do + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException + { + return fc.getResponseStream(); + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#getWriter() + */ + public Writer getWriter() throws IOException + { + return fc.getResponseWriter(); + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#setStatus(int) + */ + public void setStatus(int status) + { + // makes no sense in the JSF env + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#setCache() + */ + public void setCache(WebScriptCache cache) + { + // NOTE: not applicable + } + + /** + * @see org.alfresco.web.scripts.WebScriptResponse#setContentType(java.lang.String) + */ + public void setContentType(String contentType) + { + // Alfresco JSF framework only supports the default of text-html + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptResponse#getEncodeScriptUrlFunction(java.lang.String) + */ + public String getEncodeScriptUrlFunction(String name) + { + UIForm form = Utils.getParentForm(fc, component); + if (form == null) + { + throw new IllegalStateException("Must nest components inside UIForm to generate form submit!"); + } + String fieldId = component.getClientId(fc); + String formClientId = form.getClientId(fc); + HtmlFormRendererBase.addHiddenCommandParameter(fc, form, fieldId); + + String func = ENCODE_FUNCTION.replace("$name$", name); + func = func.replace("$formClientId$", formClientId); + func = func.replace("$fieldId$", fieldId); + return Utils.encodeJavascript(func); + } + + private static final String ENCODE_FUNCTION = + "{ $name$: function(url) {" + + " var out = '';" + + " out += \"#\\\" onclick=\\\"document.forms['$formClientId$']['$fieldId$'].value='\";" + + " out += escape(url);" + + " out += \"';document.forms['$formClientId$'].submit();return false;\";" + + " return out; } }"; +} diff --git a/source/java/org/alfresco/web/scripts/jsf/WebScriptTag.java b/source/java/org/alfresco/web/scripts/jsf/WebScriptTag.java new file mode 100644 index 0000000000..2eeea14222 --- /dev/null +++ b/source/java/org/alfresco/web/scripts/jsf/WebScriptTag.java @@ -0,0 +1,103 @@ +/* + * 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.jsf; + +import javax.faces.component.UIComponent; + +import org.alfresco.web.ui.common.tag.BaseComponentTag; + +/** + * JSF tag class for the UIWebScript component. + * + * @author Kevin Roast + */ +public class WebScriptTag extends BaseComponentTag +{ + /** + * @see javax.faces.webapp.UIComponentTag#getComponentType() + */ + @Override + public String getComponentType() + { + return "org.alfresco.faces.WebScript"; + } + + /** + * @see javax.faces.webapp.UIComponentTag#getRendererType() + */ + @Override + public String getRendererType() + { + // the component is self renderering + return null; + } + + /** + * @see javax.faces.webapp.UIComponentTag#setProperties(javax.faces.component.UIComponent) + */ + protected void setProperties(UIComponent component) + { + super.setProperties(component); + setStringProperty(component, "scriptUrl", this.scriptUrl); + setStringProperty(component, "context", this.context); + } + + /** + * @see javax.servlet.jsp.tagext.Tag#release() + */ + public void release() + { + super.release(); + this.scriptUrl = null; + this.context = null; + } + + /** + * Set the script service Url + * + * @param scriptUrl the script service Url + */ + public void setScriptUrl(String scriptUrl) + { + this.scriptUrl = scriptUrl; + } + + /** + * Set the script context + * + * @param context the script context + */ + public void setContext(String context) + { + this.context = context; + } + + + /** the script context */ + private String context; + + /** the scriptUrl */ + private String scriptUrl; +} diff --git a/source/java/org/alfresco/web/ui/common/ConstantMethodBinding.java b/source/java/org/alfresco/web/ui/common/ConstantMethodBinding.java new file mode 100644 index 0000000000..860c1e79d4 --- /dev/null +++ b/source/java/org/alfresco/web/ui/common/ConstantMethodBinding.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.web.ui.common; + +import javax.faces.component.StateHolder; +import javax.faces.context.FacesContext; +import javax.faces.el.MethodBinding; + +public class ConstantMethodBinding extends MethodBinding implements StateHolder +{ + private String outcome = null; + private boolean transientFlag = false; + + public ConstantMethodBinding() + { + } + + public ConstantMethodBinding(String yourOutcome) + { + outcome = yourOutcome; + } + + public Object invoke(FacesContext context, Object params[]) + { + return outcome; + } + + public Class getType(FacesContext context) + { + return String.class; + } + + public Object saveState(FacesContext context) + { + return outcome; + } + + public void restoreState(FacesContext context, Object state) + { + outcome = (String) state; + } + + public boolean isTransient() + { + return (this.transientFlag); + } + + public void setTransient(boolean transientFlag) + { + this.transientFlag = transientFlag; + } +} diff --git a/source/java/org/alfresco/web/ui/common/component/SelfRenderingComponent.java b/source/java/org/alfresco/web/ui/common/component/SelfRenderingComponent.java new file mode 100644 index 0000000000..049c8dc428 --- /dev/null +++ b/source/java/org/alfresco/web/ui/common/component/SelfRenderingComponent.java @@ -0,0 +1,69 @@ +/* + * 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.ui.common.component; + +import java.io.IOException; + +import javax.faces.component.UIComponentBase; +import javax.faces.context.ResponseWriter; + + +/** + * @author kevinr + */ +public abstract class SelfRenderingComponent extends UIComponentBase +{ + /** + * Default Constructor + */ + public SelfRenderingComponent() + { + // specifically set the renderer type to null to indicate to the framework + // that this component renders itself - there is no abstract renderer class + setRendererType(null); + } + + /** + * Helper to output an attribute to the output stream + * + * @param out ResponseWriter + * @param attr attribute value object (cannot be null) + * @param mapping mapping to output as e.g. style="..." + * + * @throws IOException + */ + protected static void outputAttribute(ResponseWriter out, Object attr, String mapping) + throws IOException + { + if (attr != null) + { + out.write(' '); + out.write(mapping); + out.write("=\""); + out.write(attr.toString()); + out.write('"'); + } + } +} diff --git a/source/java/org/alfresco/web/ui/common/tag/BaseComponentTag.java b/source/java/org/alfresco/web/ui/common/tag/BaseComponentTag.java new file mode 100644 index 0000000000..a5d39c8c60 --- /dev/null +++ b/source/java/org/alfresco/web/ui/common/tag/BaseComponentTag.java @@ -0,0 +1,229 @@ +/* + * 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.ui.common.tag; + +import javax.faces.FacesException; +import javax.faces.component.UICommand; +import javax.faces.component.UIComponent; +import javax.faces.el.MethodBinding; +import javax.faces.el.ValueBinding; +import javax.faces.webapp.UIComponentTag; + +import org.alfresco.web.ui.common.ConstantMethodBinding; + +/** + * @author Kevin Roast + */ +public abstract class BaseComponentTag extends UIComponentTag +{ + /** + * Helper to set an action property into a command component + * + * @param command Command component + * @param action The action method binding or outcome to set + */ + protected void setActionProperty(UICommand command, String action) + { + if (action != null) + { + if (isValueReference(action)) + { + MethodBinding vb = getFacesContext().getApplication().createMethodBinding(action, null); + command.setAction(vb); + } + else + { + MethodBinding vb = new ConstantMethodBinding(action); + command.setAction(vb); + } + } + } + + /** + * Helper to set an action listener property into a command component + * + * @param command Command component + * @param actionListener Action listener method binding + */ + protected void setActionListenerProperty(UICommand command, String actionListener) + { + if (actionListener != null) + { + if (isValueReference(actionListener)) + { + MethodBinding vb = getFacesContext().getApplication().createMethodBinding(actionListener, ACTION_CLASS_ARGS); + command.setActionListener(vb); + } + else + { + throw new FacesException("Action listener method binding incorrectly specified: " + actionListener); + } + } + } + + /** + * Helper method to set a String property value into the component. + * Respects the possibility that the property value is a Value Binding. + * + * @param component UIComponent + * @param name property string name + * @param value property string value + */ + protected void setStringProperty(UIComponent component, String name, String value) + { + if (value != null) + { + if (isValueReference(value)) + { + ValueBinding vb = getFacesContext().getApplication().createValueBinding(value); + component.setValueBinding(name, vb); + } + else + { + component.getAttributes().put(name, value); + } + } + } + + /** + * Helper method to set a String value property into the component. + * Assumes the that the property value can only be a Value Binding. + * + * @param component UIComponent + * @param name property string name + * @param value property string value binding + */ + protected void setStringBindingProperty(UIComponent component, String name, String value) + { + if (value != null) + { + if (isValueReference(value)) + { + ValueBinding vb = getFacesContext().getApplication().createValueBinding(value); + component.setValueBinding(name, vb); + } + else + { + throw new IllegalArgumentException("Property: '" + name + "' must be a value binding expression."); + } + } + } + + /** + * Helper method to set a static String property into the component. + * Assumes the that the property value can only be a static string value. + * + * @param component UIComponent + * @param name property string name + * @param value property string static value + */ + protected void setStringStaticProperty(UIComponent component, String name, String value) + { + if (value != null) + { + component.getAttributes().put(name, value); + } + } + + /** + * Helper method to set a String property as an Integer value into the component. + * Respects the possibility that the property value is a Value Binding. + * + * @param component UIComponent + * @param name property string name + * @param value property string value (an Integer will be created) + */ + protected void setIntProperty(UIComponent component, String name, String value) + { + if (value != null) + { + if (isValueReference(value)) + { + ValueBinding vb = getFacesContext().getApplication().createValueBinding(value); + component.setValueBinding(name, vb); + } + else + { + try + { + component.getAttributes().put(name, Integer.valueOf(value)); + } + catch (NumberFormatException ne) + { + throw new RuntimeException("Was expecting Int value for property '" + name + "' but passed value: " + value); + } + } + } + } + + protected void setIntStaticProperty(UIComponent component, String name, String value) + { + if (value != null) + { + try + { + component.getAttributes().put(name, Integer.valueOf(value)); + } + catch (NumberFormatException ne) + { + throw new RuntimeException("Was expecting Int value for property '" + name + "' but passed value: " + value); + } + } + } + + /** + * Helper method to set a String property as an Boolean value into the component. + * Respects the possibility that the property value is a Value Binding. + * + * @param component UIComponent + * @param name property string name + * @param value property string value (a Boolean will be created) + */ + protected void setBooleanProperty(UIComponent component, String name, String value) + { + if (value != null) + { + if (isValueReference(value)) + { + ValueBinding vb = getFacesContext().getApplication().createValueBinding(value); + component.setValueBinding(name, vb); + } + else + { + component.getAttributes().put(name, Boolean.valueOf(value)); + } + } + } + + protected void setBooleanStaticProperty(UIComponent component, String name, String value) + { + if (value != null) + { + component.getAttributes().put(name, Boolean.valueOf(value)); + } + } + + protected final static Class ACTION_CLASS_ARGS[] = {javax.faces.event.ActionEvent.class}; +} diff --git a/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java b/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java index f7ea217d75..5350083f64 100644 --- a/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java +++ b/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java @@ -36,10 +36,10 @@ import javax.faces.context.ResponseWriter; import org.alfresco.config.Config; import org.alfresco.config.ConfigService; import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.web.scripts.bean.SearchProxy; import org.alfresco.web.app.Application; import org.alfresco.web.config.OpenSearchConfigElement; import org.alfresco.web.config.OpenSearchConfigElement.EngineConfig; +import org.alfresco.web.scripts.bean.SearchProxy; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.SelfRenderingComponent; import org.springframework.web.jsf.FacesContextUtils; diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 9d4b43b196..ef61d7dea1 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -69,7 +69,6 @@ contextConfigLocation classpath:alfresco/application-context.xml - classpath:alfresco/web-framework-application-context.xml classpath:alfresco/web-client-application-context.xml classpath:alfresco/web-scripts-application-context.xml classpath:alfresco/web-pagerenderer-application-context.xml