diff --git a/config/alfresco/templates/api/KeywordSearchDescription_view_opensearchdescription.ftl b/config/alfresco/templates/api/KeywordSearchDescription_view_opensearchdescription.ftl
deleted file mode 100644
index f16dac89b8..0000000000
--- a/config/alfresco/templates/api/KeywordSearchDescription_view_opensearchdescription.ftl
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Alfresco Keyword Search
- Alfresco ${agent.edition} Keyword Search ${agent.version}
- Search Alfresco "company home" using keywords
- <#comment>IE takes first template from list, thus html response is listed first#comment>
-
-
-
- ${request.path}/images/logo/AlfrescoLogo16.ico
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/KeywordSearch_query_.ftl b/config/alfresco/templates/api/KeywordSearch_query_.ftl
deleted file mode 100644
index ad0a1fad7f..0000000000
--- a/config/alfresco/templates/api/KeywordSearch_query_.ftl
+++ /dev/null
@@ -1,13 +0,0 @@
-TYPE:"{http://www.alfresco.org/model/content/1.0}content" AND <#t>
-( <#t>
- ( <#t>
-<#list 1..terms?size as i>
- @\{http\://www.alfresco.org/model/content/1.0\}name:${terms[i - 1]}<#if (i < terms?size)> OR #if> <#t>
-#list>
- ) <#t>
- ( <#t>
-<#list 1..terms?size as i>
- TEXT:${terms[i - 1]}<#if (i < terms?size)> OR #if> <#t>
-#list>
- ) <#t>
-) <#t>
diff --git a/config/alfresco/templates/api/KeywordSearch_view_atom.ftl b/config/alfresco/templates/api/KeywordSearch_view_atom.ftl
deleted file mode 100644
index 5b714d8718..0000000000
--- a/config/alfresco/templates/api/KeywordSearch_view_atom.ftl
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
- Alfresco (${agent.edition})
- Alfresco Keyword Search: ${search.searchTerms}
- ${xmldate(date)}
- ${absurl("/images/logo/AlfrescoLogo16.ico")}
-
- ${request.authenticatedUsername!"unknown"}
-
- urn:uuid:${search.id}
- ${search.totalResults}
- ${search.startIndex}
- ${search.itemsPerPage}
-
-
-
-<#if search.startPage > 1>
-
-
-#if>
-<#if search.startPage < search.totalPages>
-
-
-#if>
-
-<#list search.results as row>
-<#attempt>
-
- ${row.name}
-
- ${absurl(row.icon16)} <#comment>TODO: What's the standard for entry icons?#comment>
- urn:uuid:${row.id}
- ${xmldate(row.properties.modified)}
- ${row.properties.description!""}
-
- ${row.properties.creator}
-
- ${row.score}
-
-<#recover>
-#attempt>
-#list>
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/KeywordSearch_view_html.ftl b/config/alfresco/templates/api/KeywordSearch_view_html.ftl
deleted file mode 100644
index 3fc5ee537f..0000000000
--- a/config/alfresco/templates/api/KeywordSearch_view_html.ftl
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
- Alfresco Keyword Search: ${search.searchTerms}
-
-
-
-
-
-
-
-
-
-
- Alfresco Keyword Search
-
-
-
-
-
- Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} visible to user ${request.authenticatedUsername!"unknown"}.
-
-
-
-
-<#list search.results as row>
-<#attempt>
-
- ${row.name}
-
- <#if row.properties.description?? == true>
-
-
- ${row.properties.description}
-
- #if>
-<#recover>
-#attempt>
-#list>
-
-
-
-
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/KeywordSearch_view_rss.ftl b/config/alfresco/templates/api/KeywordSearch_view_rss.ftl
deleted file mode 100644
index ddecbe48ad..0000000000
--- a/config/alfresco/templates/api/KeywordSearch_view_rss.ftl
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
- Alfresco Keyword Search: ${search.searchTerms}
- ${request.servicePath}/search/keyword?q=${search.searchTerms?url}&p=${search.startPage}&c=${search.itemsPerPage}&l=${search.localeId}&guest=${request.guest?string("true","")}&format=${request.format}
- Alfresco Keyword Search: ${search.searchTerms}
- ${search.localeId}
- ${xmldate(date)}
- ${xmldate(date)}
- Alfresco ${agent.edition} v${agent.version}
-
- Alfresco Search: ${search.searchTerms}
- 16
- 16
- ${absurl("/images/logo/AlfrescoLogo16.ico")}
-
- ${search.totalResults}
- ${search.startIndex}
- ${search.itemsPerPage}
-
-
-<#if search.startPage > 1>
-
-
-#if>
-<#if search.startPage < search.totalPages>
-
-
-#if>
-
-<#list search.results as row>
-<#attempt>
- -
-
${row.name}
- ${absurl(row.url)}
- ${row.properties.description!""}
- ${xmldate(row.properties.modified)}
- ${row.id}
-
-<#recover>
-#attempt>
-#list>
-
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/SearchEngines_view_atom.ftl b/config/alfresco/templates/api/SearchEngines_view_atom.ftl
deleted file mode 100644
index ccf86b0781..0000000000
--- a/config/alfresco/templates/api/SearchEngines_view_atom.ftl
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Alfresco (${agent.edition})
- Registered Search Engines
- ${xmldate(date)}
- ${request.path}/images/logo/AlfrescoLogo16.ico
-
- ${request.authenticatedUsername!"unknown"}
-
- ${request.url?xml}
-<#list engines as engine>
-
- ${engine.label}
-
- <#if engine.urlType == "description">OpenSearch Description<#else>Template URL#if> - ${engine.type}
- ${absurl(engine.url)?xml}
- ${xmldate(date)}
-
-#list>
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/SearchEngines_view_html.ftl b/config/alfresco/templates/api/SearchEngines_view_html.ftl
deleted file mode 100644
index a1999105e3..0000000000
--- a/config/alfresco/templates/api/SearchEngines_view_html.ftl
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- Alfresco Registered Search Engines
-<#list engines as engine>
-<#if engine.urlType == "description">
-
-#if>
-#list>
-
-
-
-
-
- Alfresco Registered Search Engines
-
-
-
-
- Engine URL Type Response Format
-<#list engines as engine>
-
- ${engine.label}
- <#if engine.urlType == "description">OpenSearch Description<#else>Template URL#if>
- ${engine.type}
-
-#list>
-
-
-
\ No newline at end of file
diff --git a/config/alfresco/templates/api/Services_view_html.ftl b/config/alfresco/templates/api/Services_view_html.ftl
deleted file mode 100644
index 010254d03f..0000000000
--- a/config/alfresco/templates/api/Services_view_html.ftl
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- Alfresco Web APIs
-
-
-
-
-
-
- Alfresco Web APIs
-
- Alfresco ${agent.edition} v${agent.version}
- ${services?size} services - Online documentation .
-
-
-
- Name Method URL Authentication Default Format
-<#list services as service>
- ${service.name} ${service.httpMethod} ${service.httpUri} ${service.requiredAuthentication} ${service.defaultFormat}
- [${service.description}]
-
-#list>
-
-
\ No newline at end of file
diff --git a/config/alfresco/web-api-application-context.xml b/config/alfresco/web-api-application-context.xml
index ee1e6cbeb2..500d39b840 100644
--- a/config/alfresco/web-api-application-context.xml
+++ b/config/alfresco/web-api-application-context.xml
@@ -60,14 +60,18 @@
+
+
+
+
+
+
+
+
-
-
-
-
@@ -78,14 +82,33 @@
+
+
+
-
+
-
-
+
+
+
+
+ alfresco/templates/api
+
+
+
+
+
+
+
+ web.api.ScriptedAPIService
+
+
+
+
+
@@ -95,33 +118,19 @@
-
-
-
-
-
-
-
- alfresco/templates/api
-
-
-
-
-
+
-
-
-
-
+
+
@@ -129,33 +138,23 @@
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/web/api/APIDescription.java b/source/java/org/alfresco/web/api/APIDescription.java
new file mode 100644
index 0000000000..86852ce26b
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIDescription.java
@@ -0,0 +1,123 @@
+/*
+ * 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.api;
+
+
+/**
+ * API Service
+ *
+ * @author davidc
+ */
+public interface APIDescription
+{
+ /**
+ * Gets the source document location of this service description
+ *
+ * @return document location (path)
+ */
+ public String getSourceLocation();
+
+ /**
+ * 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 APIRequest.RequiredAuthentication getRequiredAuthentication();
+
+ /**
+ * 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 URI[] getURIs();
+
+ /**
+ * Gets a URI by format
+ *
+ * @param format the format
+ * @return the URI (or null, if no URI registered for the format)
+ */
+ public URI getURI(String format);
+
+ /**
+ * Gets the default response format
+ *
+ * Note: the default response format is the first listed in the service
+ * description document
+ *
+ * @return default response format
+ */
+ public String getDefaultFormat();
+
+
+ /**
+ * API Service URL
+ *
+ * @author davidc
+ */
+ public interface URI
+ {
+ /**
+ * Gets the URI response format
+ *
+ * @return format
+ */
+ public String getFormat();
+
+ /**
+ * Gets the URI
+ *
+ * @return uri
+ */
+ public String getURI();
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/APIDescriptionImpl.java b/source/java/org/alfresco/web/api/APIDescriptionImpl.java
new file mode 100644
index 0000000000..6f61b6ec40
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIDescriptionImpl.java
@@ -0,0 +1,142 @@
+package org.alfresco.web.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.web.api.APIRequest.RequiredAuthentication;
+
+
+public class APIDescriptionImpl implements APIDescription
+{
+ private String sourceLocation;
+ private String id;
+ private String shortName;
+ private String description;
+ private RequiredAuthentication requiredAuthentication;
+ private String httpMethod;
+ private URI[] uris;
+ private String defaultFormat;
+ private Map uriByFormat;
+
+
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return this.id;
+ }
+
+ public void setShortName(String shortName)
+ {
+ this.shortName = shortName;
+ }
+
+ public String getShortName()
+ {
+ return this.shortName;
+ }
+
+ public void setDescription(String description)
+ {
+ this.description = description;
+ }
+
+ public String getDescription()
+ {
+ return this.description;
+ }
+
+ public void setRequiredAuthentication(RequiredAuthentication requiredAuthentication)
+ {
+ this.requiredAuthentication = requiredAuthentication;
+ }
+
+ public RequiredAuthentication getRequiredAuthentication()
+ {
+ return this.requiredAuthentication;
+ }
+
+ public void setMethod(String httpMethod)
+ {
+ this.httpMethod = httpMethod;
+ }
+
+ public String getMethod()
+ {
+ return this.httpMethod;
+ }
+
+ public void setUris(URI[] uris)
+ {
+ this.uriByFormat = new HashMap(uris.length);
+ for (URI uri : uris)
+ {
+ this.uriByFormat.put(uri.getFormat(), uri);
+ }
+ this.uris = uris;
+ }
+
+ public URI[] getURIs()
+ {
+ return this.uris;
+ }
+
+ public URI getURI(String format)
+ {
+ return this.uriByFormat.get(format);
+ }
+
+ public void setDefaultFormat(String defaultFormat)
+ {
+ this.defaultFormat = defaultFormat;
+ }
+
+ public String getDefaultFormat()
+ {
+ return this.defaultFormat;
+ }
+
+
+ public static class URIImpl implements APIDescription.URI
+ {
+ private String format;
+ private String uri;
+
+ public void setFormat(String format)
+ {
+ this.format = format;
+ }
+
+ public String getFormat()
+ {
+ return this.format;
+ }
+
+ public void setUri(String uri)
+ {
+ this.uri = uri;
+ }
+
+ public String getURI()
+ {
+ return this.uri;
+ }
+
+
+ }
+
+
+ public void setSourceLocation(String sourceLocation)
+ {
+ this.sourceLocation = sourceLocation;
+ }
+
+ public String getSourceLocation()
+ {
+ return this.sourceLocation;
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/APIRegistry.java b/source/java/org/alfresco/web/api/APIRegistry.java
new file mode 100644
index 0000000000..a57c83706c
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIRegistry.java
@@ -0,0 +1,30 @@
+package org.alfresco.web.api;
+
+import java.util.Collection;
+
+import javax.servlet.ServletContext;
+
+public interface APIRegistry
+{
+
+ public ServletContext getContext();
+
+ /**
+ * Gets an API Service given an HTTP Method and URI
+ *
+ * @param method
+ * @param uri
+ * @return
+ */
+ public APIServiceMatch findService(String method, String uri);
+
+ public APIService getService(String id);
+
+ public Collection getServices();
+
+ public FormatRegistry getFormatRegistry();
+
+ public APITemplateProcessor getTemplateProcessor();
+
+ //public APIScriptProcessor getScriptProcessor();
+}
diff --git a/source/java/org/alfresco/web/api/APIRequest.java b/source/java/org/alfresco/web/api/APIRequest.java
index 78a20db89e..eef534bd98 100644
--- a/source/java/org/alfresco/web/api/APIRequest.java
+++ b/source/java/org/alfresco/web/api/APIRequest.java
@@ -37,24 +37,17 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
*/
public class APIRequest extends HttpServletRequestWrapper
{
-
- /**
- * Enumerartion of HTTP Methods
- */
- public enum HttpMethod
- {
- GET;
- // TODO: Complete list...
- }
-
+ private APIServiceMatch serviceMatch;
+
+
/**
* Enumeration of "required" Authentication level
*/
public enum RequiredAuthentication
{
- None,
- Guest,
- User
+ none,
+ guest,
+ user
}
/**
@@ -62,22 +55,22 @@ public class APIRequest extends HttpServletRequestWrapper
*
* @param req
*/
- /*package*/ APIRequest(HttpServletRequest req)
+ /*package*/ APIRequest(HttpServletRequest req, APIServiceMatch serviceMatch)
{
super(req);
+ this.serviceMatch = serviceMatch;
}
/**
- * Gets the HTTP Method
+ * Gets the matching API Service for this request
*
- * @return Http Method
+ * @return the service match
*/
- public HttpMethod getHttpMethod()
+ public APIServiceMatch getServiceMatch()
{
- String method = getMethod().trim().toUpperCase();
- return HttpMethod.valueOf(method);
+ return serviceMatch;
}
-
+
/**
* Gets the Alfresco Context URL
*
@@ -109,14 +102,15 @@ public class APIRequest extends HttpServletRequestWrapper
*
* @return extension path
*/
- public String getExtensionPath(APIService service)
+ public String getExtensionPath()
{
- String servicePath = service.getHttpUri();
+ String servicePath = serviceMatch.getPath();
String extensionPath = getPathInfo();
int extIdx = extensionPath.indexOf(servicePath);
if (extIdx != -1)
{
- extensionPath = extensionPath.substring(extIdx + servicePath.length() + 1 /* exclude leading / */);
+ int extLength = (servicePath.endsWith("/") ? servicePath.length() : servicePath.length() + 1);
+ extensionPath = extensionPath.substring(extIdx + extLength);
}
return extensionPath;
}
@@ -172,13 +166,16 @@ public class APIRequest extends HttpServletRequestWrapper
public String getAgent()
{
String userAgent = getHeader("user-agent");
- if (userAgent.indexOf("Firefox/") != -1)
+ if (userAgent != null)
{
- return "Firefox";
- }
- else if (userAgent.indexOf("MSIE") != -1)
- {
- return "MSIE";
+ if (userAgent.indexOf("Firefox/") != -1)
+ {
+ return "Firefox";
+ }
+ else if (userAgent.indexOf("MSIE") != -1)
+ {
+ return "MSIE";
+ }
}
return null;
}
diff --git a/source/java/org/alfresco/web/api/APIService.java b/source/java/org/alfresco/web/api/APIService.java
index 4c6ea6da51..6b360d5890 100644
--- a/source/java/org/alfresco/web/api/APIService.java
+++ b/source/java/org/alfresco/web/api/APIService.java
@@ -33,46 +33,7 @@ import java.io.IOException;
*/
public interface APIService
{
-
- /**
- * Gets the name of this service
- *
- * @return service name
- */
- public String getName();
-
- /**
- * 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 APIRequest.RequiredAuthentication getRequiredAuthentication();
-
- /**
- * Gets the HTTP method this service is bound to
- *
- * @return HTTP method
- */
- public APIRequest.HttpMethod getHttpMethod();
-
- /**
- * Gets the HTTP uri this service is bound to
- *
- * @return HTTP uri
- */
- public String getHttpUri();
-
- /**
- * Gets the default response format
- *
- * @return response format
- */
- public String getDefaultFormat();
+ public APIDescription getDescription();
/**
* Execute service
@@ -83,5 +44,5 @@ public interface APIService
*/
public void execute(APIRequest req, APIResponse res)
throws IOException;
-
+
}
diff --git a/source/java/org/alfresco/web/api/APIServiceMatch.java b/source/java/org/alfresco/web/api/APIServiceMatch.java
new file mode 100644
index 0000000000..b2fbd994de
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIServiceMatch.java
@@ -0,0 +1,10 @@
+package org.alfresco.web.api;
+
+public interface APIServiceMatch
+{
+
+ public String getPath();
+
+ public APIService getService();
+
+}
diff --git a/source/java/org/alfresco/web/api/APIServiceRegistry.java b/source/java/org/alfresco/web/api/APIServiceRegistry.java
deleted file mode 100644
index d11bffcde8..0000000000
--- a/source/java/org/alfresco/web/api/APIServiceRegistry.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.web.api;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.aopalliance.intercept.MethodInterceptor;
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
-import org.springframework.context.ApplicationContext;
-
-
-/**
- * Registry of Web API Services methods
- *
- * @author davidc
- */
-public class APIServiceRegistry
-{
- // TODO: Support different kinds of uri resolution (e.g. regex:/search/.*)
-
- private List methods = new ArrayList();
- private List uris = new ArrayList();
- private List services = new ArrayList();
-
-
- /**
- * Construct list of API Services
- *
- * @param appContext The app context
- */
- public APIServiceRegistry(ApplicationContext appContext)
- {
- // retrieve service authenticator
- MethodInterceptor authenticator = (MethodInterceptor)appContext.getBean("web.api.Authenticator");
- MethodInterceptor serviceLogger = (MethodInterceptor)appContext.getBean("web.api.ServiceLogger");
-
- // register all API Services
- // NOTE: An API Service is one registered in Spring which is of type APIServiceImpl
- Map apiServices = appContext.getBeansOfType(APIService.class, false, false);
- for (Map.Entry apiService : apiServices.entrySet())
- {
- // retrieve service
- APIService service = apiService.getValue();
-
- // retrieve http method
- APIRequest.HttpMethod method = service.getHttpMethod();
- String httpUri = service.getHttpUri();
- if (httpUri == null || httpUri.length() == 0)
- {
- throw new APIException("Web API Service " + apiService.getKey() + " does not specify a HTTP URI mapping");
- }
-
- // wrap API Service in appropriate interceptors (e.g. authentication)
- if (serviceLogger != null && authenticator != null)
- {
- ProxyFactory authFactory = new ProxyFactory((APIService)service);
-
- // authentication
- if (service.getRequiredAuthentication() != APIRequest.RequiredAuthentication.None)
- {
- if (authenticator == null)
- {
- throw new APIException("Web API Authenticator not specified");
- }
- RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", authenticator);
- authFactory.addAdvisor(advisor);
- }
-
- // logging
- if (serviceLogger != null)
- {
- RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", serviceLogger);
- authFactory.addAdvisor(advisor);
- }
-
- service = (APIService)authFactory.getProxy();
- }
-
- // register service
- methods.add(method);
- uris.add(httpUri);
- services.add(service);
- }
- }
-
-
- /**
- * Gets an API Service given an HTTP Method and URI
- *
- * @param method The method
- * @param uri The URI
- * @return The matching service or null if there isn't a match
- */
- public APIService get(APIRequest.HttpMethod method, String uri)
- {
- APIService apiService = null;
-
- // TODO: Replace with more efficient approach
- for (int i = 0; i < services.size(); i++)
- {
- if (methods.get(i).equals(method) && uri.startsWith(uris.get(i)))
- {
- apiService = services.get(i);
- break;
- }
- }
-
- return apiService;
- }
-
-}
diff --git a/source/java/org/alfresco/web/api/APIServlet.java b/source/java/org/alfresco/web/api/APIServlet.java
index 48b495c4f8..fcff8d0a9f 100644
--- a/source/java/org/alfresco/web/api/APIServlet.java
+++ b/source/java/org/alfresco/web/api/APIServlet.java
@@ -52,7 +52,7 @@ public class APIServlet extends HttpServlet
private static final Log logger = LogFactory.getLog(APIServlet.class);
// API Services
- private APIServiceRegistry apiServiceRegistry;
+ private DeclarativeAPIRegistry apiServiceRegistry;
@Override
@@ -63,7 +63,7 @@ public class APIServlet extends HttpServlet
// Retrieve all web api services and index by http url & http method
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
initContext(context);
- apiServiceRegistry = new APIServiceRegistry(context);
+// apiServiceRegistry = new DeclarativeAPIServiceRegistry(context);
}
@@ -79,45 +79,45 @@ public class APIServlet extends HttpServlet
*/
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
- long start = System.currentTimeMillis();
- APIRequest request = new APIRequest(req);
- APIResponse response = new APIResponse(res);
-
- try
- {
- //
- // Execute appropriate service
- //
- // TODO: Handle errors (with appropriate HTTP error responses)
-
- APIRequest.HttpMethod method = request.getHttpMethod();
- String uri = request.getPathInfo();
-
- if (logger.isDebugEnabled())
- logger.debug("Processing request (" + request.getHttpMethod() + ") " + request.getRequestURL() + (request.getQueryString() != null ? "?" + request.getQueryString() : "") + " (agent: " + request.getAgent() + ")");
-
- APIService service = apiServiceRegistry.get(method, uri);
- if (service != null)
- {
- // TODO: Wrap in single transaction
- service.execute(request, response);
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("Request does not map to service.");
-
- response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- // TODO: add appropriate error detail
- }
- }
- // TODO: exception handling
- finally
- {
- long end = System.currentTimeMillis();
- if (logger.isDebugEnabled())
- logger.debug("Processed request (" + request.getHttpMethod() + ") " + request.getRequestURL() + (request.getQueryString() != null ? "?" + request.getQueryString() : "") + " in " + (end - start) + "ms");
- }
+// long start = System.currentTimeMillis();
+// APIRequest request = new APIRequest(req);
+// APIResponse response = new APIResponse(res);
+//
+// try
+// {
+// //
+// // Execute appropriate service
+// //
+// // TODO: Handle errors (with appropriate HTTP error responses)
+//
+// APIRequest.HttpMethod method = request.getHttpMethod();
+// String uri = request.getPathInfo();
+//
+// if (logger.isDebugEnabled())
+// logger.debug("Processing request (" + request.getHttpMethod() + ") " + request.getRequestURL() + (request.getQueryString() != null ? "?" + request.getQueryString() : "") + " (agent: " + request.getAgent() + ")");
+//
+// APIServiceDescription service = apiServiceRegistry.get(method, uri);
+// if (service != null)
+// {
+// // TODO: Wrap in single transaction
+// service.execute(request, response);
+// }
+// else
+// {
+// if (logger.isDebugEnabled())
+// logger.debug("Request does not map to service.");
+//
+// response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+// // TODO: add appropriate error detail
+// }
+// }
+// // TODO: exception handling
+// finally
+// {
+// long end = System.currentTimeMillis();
+// if (logger.isDebugEnabled())
+// logger.debug("Processed request (" + request.getHttpMethod() + ") " + request.getRequestURL() + (request.getQueryString() != null ? "?" + request.getQueryString() : "") + " in " + (end - start) + "ms");
+// }
}
/**
diff --git a/source/java/org/alfresco/web/api/APIStore.java b/source/java/org/alfresco/web/api/APIStore.java
new file mode 100644
index 0000000000..16a4fe3cdb
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIStore.java
@@ -0,0 +1,22 @@
+package org.alfresco.web.api;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import freemarker.cache.TemplateLoader;
+
+
+public interface APIStore
+{
+ public String getBasePath();
+
+ public String[] getDescriptionDocumentPaths();
+
+ public InputStream getDescriptionDocument(String documentPath)
+ throws IOException;
+
+ public TemplateLoader getTemplateLoader();
+
+ public ScriptLoader getScriptLoader();
+}
+
diff --git a/source/java/org/alfresco/web/api/APIStores.java b/source/java/org/alfresco/web/api/APIStores.java
new file mode 100644
index 0000000000..048f0d55e4
--- /dev/null
+++ b/source/java/org/alfresco/web/api/APIStores.java
@@ -0,0 +1,94 @@
+package org.alfresco.web.api;
+
+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;
+
+public class APIStores implements ApplicationContextAware, ApplicationListener
+{
+ private ApplicationContext applicationContext;
+ private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
+ private APITemplateProcessor templateProcessor;
+
+
+ /* (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)
+ {
+ initTemplateProcessor();
+ initScriptProcessor();
+ }
+
+ @Override
+ protected void onShutdown(ApplicationEvent event)
+ {
+ }
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
+ {
+ this.applicationContext = applicationContext;
+ this.lifecycle.setApplicationContext(applicationContext);
+ }
+
+
+ protected void initTemplateProcessor()
+ {
+ List loaders = new ArrayList();
+ for (APIStore apiStore : getAPIStores())
+ {
+ TemplateLoader loader = apiStore.getTemplateLoader();
+ if (loader == null)
+ {
+ throw new APIException("Unable to retrieve template loader for api store " + apiStore.getBasePath());
+ }
+ loaders.add(loader);
+ }
+ MultiTemplateLoader loader = new MultiTemplateLoader(loaders.toArray(new TemplateLoader[loaders.size()]));
+ templateProcessor.setTemplateLoader(loader);
+ }
+
+ protected void initScriptProcessor()
+ {
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public Collection getAPIStores()
+ {
+ return applicationContext.getBeansOfType(APIStore.class, false, false).values();
+ }
+
+ public void setTemplateProcessor(APITemplateProcessor templateProcessor)
+ {
+ this.templateProcessor = templateProcessor;
+ }
+
+ public APITemplateProcessor getTemplateProcessor()
+ {
+ return templateProcessor;
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/APITemplateProcessor.java b/source/java/org/alfresco/web/api/APITemplateProcessor.java
index d8847344af..abb21cae81 100644
--- a/source/java/org/alfresco/web/api/APITemplateProcessor.java
+++ b/source/java/org/alfresco/web/api/APITemplateProcessor.java
@@ -24,9 +24,6 @@
*/
package org.alfresco.web.api;
-import java.util.HashSet;
-import java.util.Set;
-
import org.alfresco.repo.template.FreeMarkerProcessor;
import org.alfresco.repo.template.QNameAwareObjectWrapper;
import org.alfresco.util.AbstractLifecycleBean;
@@ -54,7 +51,7 @@ import freemarker.template.TemplateExceptionHandler;
public class APITemplateProcessor extends FreeMarkerProcessor implements ApplicationContextAware, ApplicationListener
{
private ProcessorLifecycle lifecycle = new ProcessorLifecycle();
- private Set templateLoaders = new HashSet();
+ private TemplateLoader templateLoader = null;
private String defaultEncoding;
private Configuration templateConfig;
@@ -77,13 +74,13 @@ public class APITemplateProcessor extends FreeMarkerProcessor implements Applica
}
/**
- * Add a Template Loader
+ * Sets the Template Loader
*
* @param templateLoader template loader
*/
- public void addTemplateLoader(TemplateLoader templateLoader)
+ public void setTemplateLoader(TemplateLoader templateLoader)
{
- templateLoaders.add(templateLoader);
+ this.templateLoader = templateLoader;
}
/**
@@ -97,10 +94,7 @@ public class APITemplateProcessor extends FreeMarkerProcessor implements Applica
config.setCacheStorage(new MruCacheStorage(20, 100));
// setup template loaders
- for (TemplateLoader templateLoader : templateLoaders)
- {
- config.setTemplateLoader(templateLoader);
- }
+ config.setTemplateLoader(templateLoader);
// use our custom object wrapper that can deal with QNameMap objects directly
config.setObjectWrapper(new QNameAwareObjectWrapper());
diff --git a/source/java/org/alfresco/web/api/AbstractAPIService.java b/source/java/org/alfresco/web/api/AbstractAPIService.java
new file mode 100644
index 0000000000..c0fc776f7b
--- /dev/null
+++ b/source/java/org/alfresco/web/api/AbstractAPIService.java
@@ -0,0 +1,153 @@
+/*
+ * 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.api;
+
+import java.io.Writer;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.alfresco.repo.template.AbsoluteUrlMethod;
+import org.alfresco.repo.template.ISO8601DateFormatMethod;
+import org.alfresco.repo.template.UrlEncodeMethod;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.descriptor.DescriptorService;
+
+
+/**
+ * Skeleton implementation of an API Service
+ *
+ * @author davidc
+ */
+public abstract class AbstractAPIService implements APIService
+{
+ // dependencies
+ private APIRegistry apiRegistry;
+ private APIDescription apiDescription;
+ private ServiceRegistry serviceRegistry;
+ private DescriptorService descriptorService;
+
+ //
+ // Initialisation
+ //
+
+ final public void setServiceRegistry(ServiceRegistry serviceRegistry)
+ {
+ this.serviceRegistry = serviceRegistry;
+ }
+
+ final public void setDescriptorService(DescriptorService descriptorService)
+ {
+ this.descriptorService = descriptorService;
+ }
+
+ final public void setDescription(APIDescription apiDescription)
+ {
+ this.apiDescription = apiDescription;
+ }
+
+ public void init(APIRegistry apiRegistry)
+ {
+ this.apiRegistry = apiRegistry;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.api.APIService#getServiceDescription()
+ */
+ final public APIDescription getDescription()
+ {
+ return this.apiDescription;
+ }
+
+ //
+ // Service Implementation Helpers
+ //
+
+ final public APIRegistry getAPIRegistry()
+ {
+ return this.apiRegistry;
+ }
+
+ final public ServiceRegistry getServiceRegistry()
+ {
+ return this.serviceRegistry;
+ }
+
+ final public DescriptorService getDescriptorService()
+ {
+ return this.descriptorService;
+ }
+
+
+ //
+ // Basic Templating Support
+ //
+
+
+ /**
+ * Create a basic API model
+ *
+ * @param req api request
+ * @param res api response
+ * @return template model
+ */
+ final protected Map createAPIModel(APIRequest req, APIResponse res)
+ {
+ Map model = new HashMap(7, 1.0f);
+ model.put("xmldate", new ISO8601DateFormatMethod());
+ model.put("absurl", new AbsoluteUrlMethod(req.getPath()));
+ model.put("urlencode", new UrlEncodeMethod());
+ model.put("date", new Date());
+ model.put("agent", descriptorService.getServerDescriptor());
+ model.put("request", req);
+ model.put("response", res);
+ 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)
+ {
+ getAPIRegistry().getTemplateProcessor().process(templatePath, model, writer);
+ }
+
+ /**
+ * 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)
+ {
+ getAPIRegistry().getTemplateProcessor().processString(template, model, writer);
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/AlfWebClientAuthenticator.java b/source/java/org/alfresco/web/api/AlfWebClientAuthenticator.java
index 2befbebcb0..f58fe36936 100644
--- a/source/java/org/alfresco/web/api/AlfWebClientAuthenticator.java
+++ b/source/java/org/alfresco/web/api/AlfWebClientAuthenticator.java
@@ -80,6 +80,7 @@ public class AlfWebClientAuthenticator implements MethodInterceptor, APIContextA
APIRequest request = (APIRequest)args[0];
APIResponse response = (APIResponse)args[1];
APIService service = (APIService)invocation.getThis();
+ APIDescription description = service.getDescription();
AuthenticationStatus status = null;
try
@@ -102,7 +103,7 @@ public class AlfWebClientAuthenticator implements MethodInterceptor, APIContextA
if (logger.isDebugEnabled())
{
- logger.debug("Service authentication required: " + service.getRequiredAuthentication());
+ logger.debug("Service authentication required: " + description.getRequiredAuthentication());
logger.debug("Guest login: " + isGuest);
logger.debug("Ticket provided: " + (ticket != null && ticket.length() > 0));
}
@@ -116,7 +117,7 @@ public class AlfWebClientAuthenticator implements MethodInterceptor, APIContextA
}
else
{
- if (isGuest && service.getRequiredAuthentication() == APIRequest.RequiredAuthentication.Guest)
+ if (isGuest && description.getRequiredAuthentication() == APIRequest.RequiredAuthentication.guest)
{
if (logger.isDebugEnabled())
logger.debug("Authenticating as Guest");
diff --git a/source/java/org/alfresco/web/api/BasicAuthenticator.java b/source/java/org/alfresco/web/api/BasicAuthenticator.java
index 1c7c7f2a43..2554a1e648 100644
--- a/source/java/org/alfresco/web/api/BasicAuthenticator.java
+++ b/source/java/org/alfresco/web/api/BasicAuthenticator.java
@@ -67,6 +67,7 @@ public class BasicAuthenticator implements MethodInterceptor
Object[] args = invocation.getArguments();
APIRequest request = (APIRequest)args[0];
APIService service = (APIService)invocation.getThis();
+ APIDescription description = service.getDescription();
try
{
@@ -87,14 +88,14 @@ public class BasicAuthenticator implements MethodInterceptor
if (logger.isDebugEnabled())
{
- logger.debug("Service authentication required: " + service.getRequiredAuthentication());
+ logger.debug("Service authentication required: " + description.getRequiredAuthentication());
logger.debug("Guest login: " + isGuest);
logger.debug("Authorization provided (overrides Guest login): " + (authorization != null && authorization.length() > 0));
}
// authenticate as guest, if service allows
if (((authorization == null || authorization.length() == 0) || isGuest)
- && service.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.Guest))
+ && description.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.guest))
{
if (logger.isDebugEnabled())
logger.debug("Authenticating as Guest");
@@ -133,7 +134,7 @@ public class BasicAuthenticator implements MethodInterceptor
// assume username and password passed
if (parts[0].equals(AuthenticationUtil.getGuestUserName()))
{
- if (service.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.Guest))
+ if (description.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.guest))
{
authenticationService.authenticateAsGuest();
authorized = true;
diff --git a/source/java/org/alfresco/web/api/ClassPathAPIStore.java b/source/java/org/alfresco/web/api/ClassPathAPIStore.java
new file mode 100644
index 0000000000..5c6c5a30af
--- /dev/null
+++ b/source/java/org/alfresco/web/api/ClassPathAPIStore.java
@@ -0,0 +1,116 @@
+package org.alfresco.web.api;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+
+import freemarker.cache.FileTemplateLoader;
+import freemarker.cache.TemplateLoader;
+
+
+public class ClassPathAPIStore implements APIStore, InitializingBean
+{
+ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ private String classPath;
+ private String classPathDir;
+
+
+ public void setClassPath(String classPath)
+ {
+ this.classPath = classPath;
+ }
+
+ public void afterPropertiesSet()
+ throws Exception
+ {
+ ClassPathResource resource = new ClassPathResource(classPath);
+ classPathDir = resource.getURL().toExternalForm();
+ }
+
+ public String getBasePath()
+ {
+ return "classpath:" + classPath;
+ }
+
+
+ public String[] getDescriptionDocumentPaths()
+ {
+ String[] paths = null;
+
+ try
+ {
+ Resource[] resources = resolver.getResources("classpath*:" + classPath + "/**/*_desc.xml");
+ paths = new String[resources.length];
+ int i = 0;
+ for (Resource resource : resources)
+ {
+ paths[i++] = resource.getURL().toExternalForm().substring(classPathDir.length());
+ }
+ }
+ catch(IOException e)
+ {
+ // Note: Ignore: no service description documents found
+ paths = new String[0];
+ }
+
+ return paths;
+ }
+
+
+ public InputStream getDescriptionDocument(String documentPath)
+ throws IOException
+ {
+ DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
+ Resource resource = resourceLoader.getResource(classPathDir + "/" + documentPath);
+ return resource.getInputStream();
+ }
+
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ ClassPathAPIStore store = new ClassPathAPIStore();
+ store.setClassPath("alfresco/templates/api");
+ store.afterPropertiesSet();
+ String[] paths = store.getDescriptionDocumentPaths();
+ InputStream is = store.getDescriptionDocument(paths[0]);
+ is.close();
+ TemplateLoader loader = store.getTemplateLoader();
+ Object obj = loader.findTemplateSource("KeywordSearch_view_atom.ftl");
+ }
+
+ public TemplateLoader getTemplateLoader()
+ {
+ FileTemplateLoader loader = null;
+ try
+ {
+ File classPathFile = new File(new URI(classPathDir));
+ loader = new FileTemplateLoader(classPathFile);
+ }
+ catch (URISyntaxException e)
+ {
+ // Note: Can't establish loader, so return null
+ }
+ catch (IOException e)
+ {
+ // Note: Can't establish loader, so return null
+ }
+ return loader;
+ }
+
+ public ScriptLoader getScriptLoader()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+}
diff --git a/source/java/org/alfresco/web/api/DeclarativeAPIRegistry.java b/source/java/org/alfresco/web/api/DeclarativeAPIRegistry.java
new file mode 100644
index 0000000000..cf41dcb882
--- /dev/null
+++ b/source/java/org/alfresco/web/api/DeclarativeAPIRegistry.java
@@ -0,0 +1,454 @@
+/*
+ * 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.api;
+
+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.web.api.APIDescription.URI;
+import org.alfresco.web.api.APIRequest.RequiredAuthentication;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+
+/**
+ * Registry of Web API Services methods
+ *
+ * @author davidc
+ */
+public class DeclarativeAPIRegistry implements APIRegistry, ApplicationContextAware, APIContextAware
+{
+ // TODO: Support different kinds of uri resolution (e.g. regex:/search/.*) ??
+
+
+ // Logger
+ private static final Log logger = LogFactory.getLog(DeclarativeAPIRegistry.class);
+
+ private ApplicationContext applicationContext;
+ private ServletContext servletContext;
+ private String defaultServiceImpl;
+ private MethodInterceptor authenticator;
+ private MethodInterceptor serviceLogger;
+ private FormatRegistry formatRegistry;
+ private APIStores stores;
+
+
+ // map of services by service id
+ // NOTE: The map is sorted by id (ascending order)
+ private Map servicesById = new TreeMap();
+
+ // map of services by url
+ // NOTE: The map is sorted by url (descending order)
+ private Map servicesByURL = new TreeMap(Collections.reverseOrder());
+
+
+ public void setAuthenticator(MethodInterceptor authenticator)
+ {
+ this.authenticator = authenticator;
+ }
+
+ public void setServiceLogger(MethodInterceptor serviceLogger)
+ {
+ this.serviceLogger = serviceLogger;
+ }
+
+ public void setDefaultServiceImpl(String defaultServiceImpl)
+ {
+ this.defaultServiceImpl = defaultServiceImpl;
+ }
+
+ public void setStores(APIStores stores)
+ {
+ this.stores = stores;
+ }
+
+
+
+
+ public void initServices()
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Initialising Web API services");
+
+ // clear currently registered services
+ servicesById.clear();
+ servicesByURL.clear();
+
+ // register services
+ for (APIStore apiStore : stores.getAPIStores())
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("Locating services within " + apiStore.getBasePath());
+
+ String basePath = apiStore.getBasePath();
+ String[] serviceDescPaths = apiStore.getDescriptionDocumentPaths();
+ for (String serviceDescPath : serviceDescPaths)
+ {
+ // build service description
+ APIDescription serviceDesc = null;
+ InputStream serviceDescIS = null;
+ try
+ {
+ serviceDescIS = apiStore.getDescriptionDocument(serviceDescPath);
+ serviceDesc = createServiceDescription(basePath, serviceDescPath, serviceDescIS);
+ }
+ catch(IOException e)
+ {
+ throw new APIException("Failed to read service description document " + apiStore.getBasePath() + serviceDescPath, e);
+ }
+ finally
+ {
+ try
+ {
+ serviceDescIS.close();
+ }
+ catch(IOException e)
+ {
+ // NOTE: ignore close exception
+ }
+ }
+
+ // determine if service description has been registered
+ String id = serviceDesc.getId();
+ if (servicesById.containsKey(id))
+ {
+ // move to next service
+ if (logger.isDebugEnabled())
+ {
+ APIService existingService = servicesById.get(id);
+ logger.debug("Service description document " + existingService.getDescription().getSourceLocation() + " overridden by " + serviceDesc.getSourceLocation());
+ }
+ continue;
+ }
+
+ // construct service implementation
+ String serviceImplName = (applicationContext.containsBean("web.api.services." + id)) ? "web.api.services." + id : defaultServiceImpl;
+ AbstractAPIService serviceImpl = (AbstractAPIService)applicationContext.getBean(serviceImplName);
+ serviceImpl.setDescription(serviceDesc);
+ serviceImpl.init(this);
+
+ // wrap service implementation in appropriate interceptors (e.g. authentication)
+ APIService serviceImplIF = (APIService)serviceImpl;
+ if (serviceLogger != null && authenticator != null)
+ {
+ ProxyFactory authFactory = new ProxyFactory();
+ authFactory.addInterface(APIService.class);
+ authFactory.setTarget(serviceImplIF);
+
+ // authentication interceptor
+ if (serviceDesc.getRequiredAuthentication() != APIRequest.RequiredAuthentication.none)
+ {
+ if (authenticator == null)
+ {
+ throw new APIException("Web API Authenticator not specified");
+ }
+ RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", authenticator);
+ authFactory.addAdvisor(advisor);
+ }
+
+ // logging interceptor
+ if (serviceLogger != null)
+ {
+ RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", serviceLogger);
+ authFactory.addAdvisor(advisor);
+ }
+
+ serviceImplIF = (APIService)authFactory.getProxy();
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Found service " + serviceDescPath + " (id: " + id + ", impl: " + serviceImplName + ")");
+
+ // register service and its urls
+ servicesById.put(id, serviceImplIF);
+ for (URI uri : serviceDesc.getURIs())
+ {
+ // establish static part of url template
+ String uriTemplate = uri.getURI();
+ int queryArgIdx = uriTemplate.indexOf('?');
+ if (queryArgIdx != -1)
+ {
+ uriTemplate = uriTemplate.substring(0, queryArgIdx);
+ }
+ int tokenIdx = uriTemplate.indexOf('{');
+ if (tokenIdx != -1)
+ {
+ uriTemplate = uriTemplate.substring(0, tokenIdx);
+ }
+
+ // index service by static part of url (ensuring no other service has already claimed the url)
+ String uriIdx = serviceDesc.getMethod().toString() + ":" + uriTemplate;
+ if (servicesByURL.containsKey(uriIdx))
+ {
+ APIService existingService = servicesByURL.get(uriIdx);
+ if (!existingService.getDescription().getId().equals(serviceDesc.getId()))
+ {
+ throw new APIException("Service document " + existingService.getDescription().getSourceLocation() + " already defines the url '" + uriIdx);
+ }
+ }
+ else
+ {
+ servicesByURL.put(uriIdx, serviceImplIF);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Registered Web API URL '" + uriIdx + "'");
+ }
+ }
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Registered " + servicesById.size() + " services; " + servicesByURL.size() + " URLs");
+ }
+
+ private APIDescription createServiceDescription(String basePath, String serviceDescPath, InputStream serviceDoc)
+ {
+ SAXReader reader = new SAXReader();
+ try
+ {
+ Document document = reader.read(serviceDoc);
+ Element rootElement = document.getRootElement();
+ if (!rootElement.getName().equals("servicedescription"))
+ {
+ throw new APIException("Expected root element - found <" + rootElement.getName() + ">");
+ }
+
+ // retrieve id
+ String id = serviceDescPath.substring(0, serviceDescPath.lastIndexOf("_desc.xml")).replace('/', '.');
+
+ // retrieve http method
+ int methodIdx = id.lastIndexOf('_');
+ if (methodIdx == id.length() - 1)
+ {
+ throw new APIException("Unable to establish HTTP Method from service description: naming convention must be __desc.xml");
+ }
+ String method = id.substring(id.lastIndexOf('_') + 1).toUpperCase();
+
+ // retrieve short name
+ Element shortNameElement = rootElement.element("shortname");
+ if (shortNameElement == null || shortNameElement.getTextTrim() == null || shortNameElement.getTextTrim().length() == 0)
+ {
+ throw new APIException("Expected value");
+ }
+ String shortName = shortNameElement.getTextTrim();
+
+ // retrieve description
+ Element descriptionElement = rootElement.element("description");
+ String description = descriptionElement.getTextTrim();
+
+ // retrieve urls
+ List urlElements = rootElement.elements("url");
+ if (urlElements == null || urlElements.size() == 0)
+ {
+ throw new APIException("Expected at one element");
+ }
+ List uris = new ArrayList();
+ Iterator iterElements = urlElements.iterator();
+ while(iterElements.hasNext())
+ {
+ // retrieve url element
+ Element urlElement = (Element)iterElements.next();
+
+ // retrieve url mimetype
+ String format = urlElement.attributeValue("format");
+ if (format == null)
+ {
+ // default to unspecified format
+ format = "";
+ }
+
+ // retrieve url template
+ String template = urlElement.attributeValue("template");
+ if (template == null || template.length() == 0)
+ {
+ throw new APIException("Expected template attribute on element");
+ }
+
+ APIDescriptionImpl.URIImpl uriImpl = new APIDescriptionImpl.URIImpl();
+ uriImpl.setFormat(format);
+ uriImpl.setUri(template);
+ uris.add(uriImpl);
+ }
+
+ // 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 APIException("Expected value");
+ }
+ reqAuth = RequiredAuthentication.valueOf(reqAuthStr);
+ if (reqAuth == null)
+ {
+ throw new APIException("Authentication '" + reqAuthStr + "' is not a valid value");
+ }
+ }
+
+ // construct service description
+ APIDescriptionImpl serviceDesc = new APIDescriptionImpl();
+ serviceDesc.setSourceLocation(basePath + "/" + serviceDescPath);
+ serviceDesc.setId(id);
+ serviceDesc.setShortName(shortName);
+ serviceDesc.setDescription(description);
+ serviceDesc.setRequiredAuthentication(reqAuth);
+ serviceDesc.setMethod(method);
+ serviceDesc.setUris(uris.toArray(new APIDescription.URI[uris.size()]));
+ serviceDesc.setDefaultFormat(uris.get(0).getFormat());
+ return serviceDesc;
+ }
+ catch(DocumentException e)
+ {
+ throw new APIException("Failed to parse service description document " + serviceDescPath, e);
+ }
+ catch(APIException e)
+ {
+ throw new APIException("Failed to parise service description document " + serviceDescPath, e);
+ }
+ }
+
+
+ /**
+ * Gets an API Service given an HTTP Method and URI
+ *
+ * @param method
+ * @param uri
+ * @return
+ */
+ public APIServiceMatch findService(String method, String uri)
+ {
+ // TODO: Replace with more efficient approach
+ DeclarativeAPIServiceMatch apiServiceMatch = null;
+ String match = method.toString().toUpperCase() + ":" + uri;
+ for (Map.Entry service : servicesByURL.entrySet())
+ {
+ String indexedPath = service.getKey();
+ if (match.startsWith(indexedPath))
+ {
+ String matchPath = indexedPath.substring(indexedPath.indexOf(':') +1);
+ apiServiceMatch = new DeclarativeAPIServiceMatch(matchPath, service.getValue());
+ break;
+ }
+ }
+ return apiServiceMatch;
+ }
+
+
+ public ServletContext getContext()
+ {
+ return servletContext;
+ }
+
+
+ public APIService getService(String id)
+ {
+ return servicesById.get(id);
+ }
+
+
+ public void setFormatRegistry(FormatRegistry formatRegistry)
+ {
+ this.formatRegistry = formatRegistry;
+ }
+
+
+ public FormatRegistry getFormatRegistry()
+ {
+ return this.formatRegistry;
+ }
+
+
+ public APITemplateProcessor getTemplateProcessor()
+ {
+ return this.stores.getTemplateProcessor();
+ }
+
+
+ public void setAPIContext(ServletContext context)
+ {
+ this.servletContext = context;
+ }
+
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
+ {
+ this.applicationContext = applicationContext;
+ }
+
+
+ public Collection getServices()
+ {
+ return servicesById.values();
+ }
+
+
+ public static class DeclarativeAPIServiceMatch implements APIServiceMatch
+ {
+ private String path;
+ private APIService service;
+
+
+ public DeclarativeAPIServiceMatch(String path, APIService service)
+ {
+ this.path = path;
+ this.service = service;
+ }
+
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public APIService getService()
+ {
+ return service;
+ }
+
+ }
+
+
+}
diff --git a/source/java/org/alfresco/web/api/ScriptLoader.java b/source/java/org/alfresco/web/api/ScriptLoader.java
new file mode 100644
index 0000000000..8903d658d7
--- /dev/null
+++ b/source/java/org/alfresco/web/api/ScriptLoader.java
@@ -0,0 +1,10 @@
+package org.alfresco.web.api;
+
+import org.alfresco.service.cmr.repository.ScriptLocation;
+
+public interface ScriptLoader
+{
+
+ ScriptLocation getScriptLocation(String path);
+
+}
diff --git a/source/java/org/alfresco/web/api/services/APIServiceTemplateImpl.java b/source/java/org/alfresco/web/api/ScriptedAPIService.java
similarity index 59%
rename from source/java/org/alfresco/web/api/services/APIServiceTemplateImpl.java
rename to source/java/org/alfresco/web/api/ScriptedAPIService.java
index 87656000b7..dae8320d40 100644
--- a/source/java/org/alfresco/web/api/services/APIServiceTemplateImpl.java
+++ b/source/java/org/alfresco/web/api/ScriptedAPIService.java
@@ -1,147 +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.api.services;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Map;
-
-import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.service.cmr.repository.TemplateException;
-import org.alfresco.web.api.APIException;
-import org.alfresco.web.api.APIRequest;
-import org.alfresco.web.api.APIResponse;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-
-/**
- * Template based implementation of an API Service
- *
- * @author davidc
- */
-public abstract class APIServiceTemplateImpl extends APIServiceImpl
-{
- // Logger
- private static final Log logger = LogFactory.getLog(APIServiceTemplateImpl.class);
-
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#execute(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse)
- */
- public void execute(APIRequest req, APIResponse res) throws IOException
- {
- // construct data model for template
- Map model = createAPIModel(req, res);
- model = createModel(req, res, model);
-
- // process requested format
- String format = req.getFormat();
- if (format == null || format.length() == 0)
- {
- format = getDefaultFormat();
- }
- String mimetype = getFormatRegistry().getMimeType(req.getAgent(), format);
- if (mimetype == null)
- {
- throw new APIException("API format '" + format + "' does not exist");
- }
-
- // render output
- res.setContentType(mimetype + ";charset=UTF-8");
-
- if (logger.isDebugEnabled())
- logger.debug("Response content type: " + mimetype);
-
- try
- {
- renderTemplate(null, format, model, res.getWriter());
- }
- catch(TemplateException e)
- {
- throw new APIException("Failed to process format '" + format + "'", e);
- }
- }
-
-
- /**
- * Create a custom service model
- *
- * @param req API request
- * @param res API response
- * @param model basic API model
- * @return custom service model
- */
- protected abstract Map createModel(APIRequest req, APIResponse res, Map model);
-
-
- /**
- * Render a template to the API Response
- *
- * @param type type of template (null defaults to type VIEW)
- * @param format template format (null, default format)
- * @param model data model to render
- * @param writer where to output
- */
- protected void renderTemplate(String type, String format, Map model, Writer writer)
- {
- type = (type == null) ? "view" : type;
- format = (format == null) ? "" : format;
- String templatePath = (this.getClass().getSimpleName() + "_" + type + "_" + format).replace(".", "/") + ".ftl";
-
- if (logger.isDebugEnabled())
- logger.debug("Rendering service template '" + templatePath + "'");
-
- renderTemplate(templatePath, model, writer);
- }
-
-
- /**
- * Simple test that can be executed outside of web context
- */
- /*package*/ void test(final String format)
- throws IOException
- {
- AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork()
- {
- public Object doWork()
- {
- // create test model
- Map model = createTestModel();
-
- // render service template to string
- StringWriter rendition = new StringWriter();
- PrintWriter writer = new PrintWriter(rendition);
- renderTemplate(null, format, model, writer);
- System.out.println(rendition.toString());
-
- return null;
- }
- }, AuthenticationUtil.getSystemUserName());
- }
-
-}
+/*
+ * 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.api;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.alfresco.service.cmr.repository.TemplateException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Script based implementation of an API Service
+ *
+ * @author davidc
+ */
+public class ScriptedAPIService extends AbstractAPIService
+{
+ // Logger
+ private static final Log logger = LogFactory.getLog(ScriptedAPIService.class);
+
+ private String baseTemplatePath;
+
+
+ @Override
+ public void init(APIRegistry apiRegistry)
+ {
+ super.init(apiRegistry);
+ baseTemplatePath = getDescription().getId().replace('.', '/');
+
+ // TODO: Test for .js script
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.api.APIService#execute(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse)
+ */
+ final public void execute(APIRequest req, APIResponse res) throws IOException
+ {
+ // construct data model for template
+ Map model = createAPIModel(req, res);
+ model = createModel(req, res, model);
+
+ // TODO: execute script if it exists
+
+ // process requested format
+ String format = req.getFormat();
+ if (format == null || format.length() == 0)
+ {
+ format = getDescription().getDefaultFormat();
+ }
+
+ String mimetype = getAPIRegistry().getFormatRegistry().getMimeType(req.getAgent(), format);
+ if (mimetype == null)
+ {
+ throw new APIException("API format '" + format + "' is not registered");
+ }
+
+ // render output
+ res.setContentType(mimetype + ";charset=UTF-8");
+
+ if (logger.isDebugEnabled())
+ logger.debug("Response content type: " + mimetype);
+
+ try
+ {
+ renderFormatTemplate(format, model, res.getWriter());
+ }
+ catch(TemplateException e)
+ {
+ throw new APIException("Failed to process format '" + format + "'", e);
+ }
+ }
+
+
+ /**
+ * Create a custom service model
+ *
+ * @param req API request
+ * @param res API response
+ * @param model basic API model
+ * @return custom service model
+ */
+ protected Map createModel(APIRequest req, APIResponse res, Map model)
+ {
+ return model;
+ }
+
+
+ /**
+ * Render a template (of given format) to the API 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 = baseTemplatePath + "_" + format + ".ftl";
+
+ if (logger.isDebugEnabled())
+ logger.debug("Rendering service template '" + templatePath + "'");
+
+ renderTemplate(templatePath, model, writer);
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/ServiceLogger.java b/source/java/org/alfresco/web/api/ServiceLogger.java
index ead62cc75e..d3d6d91072 100644
--- a/source/java/org/alfresco/web/api/ServiceLogger.java
+++ b/source/java/org/alfresco/web/api/ServiceLogger.java
@@ -53,13 +53,14 @@ public class ServiceLogger implements MethodInterceptor
if (logger.isDebugEnabled())
{
APIService service = (APIService)invocation.getThis();
+ APIDescription description = service.getDescription();
String user = AuthenticationUtil.getCurrentUserName();
String locale = I18NUtil.getLocale().toString();
- logger.debug("Invoking service " + service.getName() + (user == null ? " (unauthenticated)" : " (authenticated as " + user + ")" + " (" + locale + ")"));
+ logger.debug("Invoking service " + description.getId() + (user == null ? " (unauthenticated)" : " (authenticated as " + user + ")" + " (" + locale + ")"));
long start = System.currentTimeMillis();
retVal = invocation.proceed();
long end = System.currentTimeMillis();
- logger.debug("Service " + service.getName() + " executed in " + (end - start) + "ms");
+ logger.debug("Service " + description.getId() + " executed in " + (end - start) + "ms");
}
else
{
diff --git a/source/java/org/alfresco/web/api/SystemAuthenticator.java b/source/java/org/alfresco/web/api/SystemAuthenticator.java
new file mode 100644
index 0000000000..4732be5888
--- /dev/null
+++ b/source/java/org/alfresco/web/api/SystemAuthenticator.java
@@ -0,0 +1,94 @@
+/*
+ * 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.api;
+
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * System Authentication Interceptor
+ *
+ * @author davidc
+ */
+public class SystemAuthenticator implements MethodInterceptor
+{
+ // Logger
+ private static final Log logger = LogFactory.getLog(SystemAuthenticator.class);
+
+
+ /* (non-Javadoc)
+ * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
+ */
+ public Object invoke(MethodInvocation invocation)
+ throws Throwable
+ {
+ String currentUser = null;
+ Object retVal = null;
+
+ try
+ {
+ //
+ // Determine if user already authenticated
+ //
+
+ currentUser = AuthenticationUtil.getCurrentUserName();
+ if (logger.isDebugEnabled())
+ logger.debug("Current authentication: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
+
+ //
+ // Force system user
+ //
+
+ if (logger.isDebugEnabled())
+ logger.debug("Authenticating as System");
+
+ AuthenticationUtil.setSystemUserAsCurrentUser();
+
+ //
+ // Invoke service
+ //
+
+ retVal = invocation.proceed();
+ }
+ finally
+ {
+ AuthenticationUtil.clearCurrentSecurityContext();
+ if (currentUser != null)
+ {
+ AuthenticationUtil.setCurrentUser(currentUser);
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Authentication reset: " + (currentUser == null ? "unauthenticated" : "authenticated as " + currentUser));
+ }
+
+ return retVal;
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/TemplateClassPathSet.java b/source/java/org/alfresco/web/api/TemplateClassPathSet.java
deleted file mode 100644
index 5ef8a39089..0000000000
--- a/source/java/org/alfresco/web/api/TemplateClassPathSet.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.web.api;
-
-import java.io.File;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.core.io.DefaultResourceLoader;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-
-import freemarker.cache.FileTemplateLoader;
-
-
-/**
- * A set of template class paths
- *
- * @author davidc
- */
-public class TemplateClassPathSet implements InitializingBean
-{
- // Logger
- private static final Log logger = LogFactory.getLog(TemplateClassPathSet.class);
-
- private Set classPaths;
- private APITemplateProcessor templateProcessor;
- private ResourceLoader resourceLoader;
-
- /**
- * Construct
- */
- public TemplateClassPathSet()
- {
- resourceLoader = new DefaultResourceLoader();
- }
-
- /**
- * Sets the Template Processor
- *
- * @param templateProcessor
- */
- public void setTemplateProcessor(APITemplateProcessor templateProcessor)
- {
- this.templateProcessor = templateProcessor;
- }
-
- /**
- * Sets the paths
- *
- * @param classPaths
- */
- public void setPaths(Set classPaths)
- {
- this.classPaths = classPaths;
- }
-
- /* (non-Javadoc)
- * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
- */
- public void afterPropertiesSet() throws Exception
- {
- // Add class paths to template processor
- for (String classPath : classPaths)
- {
- Resource resource = resourceLoader.getResource(classPath);
- if (resource.exists())
- {
- File file = resource.getFile();
- templateProcessor.addTemplateLoader(new FileTemplateLoader(file));
-
- if (logger.isDebugEnabled())
- logger.debug("Registered template classpath '" + classPath);
- }
- else if (logger.isWarnEnabled())
- {
- logger.warn("Template classpath '" + classPath + "' does not exist");
- }
- }
- }
-
-}
diff --git a/source/java/org/alfresco/web/api/TestAPIServer.java b/source/java/org/alfresco/web/api/TestAPIServer.java
new file mode 100644
index 0000000000..3901b95eee
--- /dev/null
+++ b/source/java/org/alfresco/web/api/TestAPIServer.java
@@ -0,0 +1,214 @@
+package org.alfresco.web.api;
+
+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 org.alfresco.i18n.I18NUtil;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+public class TestAPIServer
+{
+ /**
+ * The reader for interaction.
+ */
+ private BufferedReader fIn;
+
+ private APIRegistry apiRegistry;
+
+ /**
+ * Last command issued
+ */
+ private String lastCommand = null;
+
+
+
+
+ /**
+ * Main entry point.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ TestAPIServer test = new TestAPIServer();
+ test.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);
+ }
+ }
+
+ /**
+ * Make up a new console.
+ */
+ public TestAPIServer()
+ {
+ fIn = new BufferedReader(new InputStreamReader(System.in));
+ String[] CONFIG_LOCATIONS = new String[] { "classpath:alfresco/application-context.xml", "classpath:alfresco/web-api-application-context.xml" };
+ ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS);
+ DeclarativeAPIRegistry testAPIRegistry = (DeclarativeAPIRegistry)context.getBean("web.api.test.Registry");
+ testAPIRegistry.initServices();
+ apiRegistry = testAPIRegistry;
+ }
+
+ /**
+ * A Read-Eval-Print loop.
+ */
+ public void rep()
+ {
+ // accept commands
+ 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("");
+ }
+ }
+ }
+
+ /**
+ * 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 interpretCommand(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"))
+ {
+ // TODO:
+ String helpFile = I18NUtil.getMessage("test_service.help");
+ 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("req"))
+ {
+ if (command.length < 2)
+ {
+ return "Syntax Error.\n";
+ }
+
+ String uri = command[1];
+ MockHttpServletRequest req = createRequest("get", uri);
+ MockHttpServletResponse res = new MockHttpServletResponse();
+
+ APIServiceMatch match = apiRegistry.findService(req.getMethod(), uri);
+ if (match == null)
+ {
+ throw new APIException("No service bound to uri '" + uri + "'");
+ }
+
+ APIRequest apiReq = new APIRequest(req, match);
+ APIResponse apiRes = new APIResponse(res);
+ match.getService().execute(apiReq, apiRes);
+ bout.write(res.getContentAsByteArray());
+ out.println();
+ }
+
+ out.flush();
+ String retVal = new String(bout.toByteArray());
+ out.close();
+ return retVal;
+ }
+
+
+ private MockHttpServletRequest createRequest(String method, String uri)
+ {
+ MockHttpServletRequest req = new MockHttpServletRequest("get", uri);
+
+ // set parameters
+ 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) ? parts[1] : null);
+ }
+ }
+
+ // set path info
+ req.setPathInfo(iArgIndex == -1 ? uri : uri.substring(0, iArgIndex));
+
+ return req;
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/services/APIServiceImpl.java b/source/java/org/alfresco/web/api/services/APIServiceImpl.java
deleted file mode 100644
index 1b5d1cdfa7..0000000000
--- a/source/java/org/alfresco/web/api/services/APIServiceImpl.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.web.api.services;
-
-import java.io.Writer;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.ServletContext;
-
-import org.alfresco.repo.template.AbsoluteUrlMethod;
-import org.alfresco.repo.template.ISO8601DateFormatMethod;
-import org.alfresco.repo.template.UrlEncodeMethod;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.repository.TemplateProcessor;
-import org.alfresco.service.descriptor.DescriptorService;
-import org.alfresco.web.api.APIContextAware;
-import org.alfresco.web.api.APIRequest;
-import org.alfresco.web.api.APIResponse;
-import org.alfresco.web.api.APIService;
-import org.alfresco.web.api.FormatRegistry;
-import org.springframework.beans.factory.BeanNameAware;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-
-
-/**
- * Skeleton implementation of an API Service
- *
- * @author davidc
- */
-public abstract class APIServiceImpl implements BeanNameAware, APIService, APIContextAware
-{
- private String name;
- private String uri;
-
- // dependencies
- private ServletContext context;
- private ServiceRegistry serviceRegistry;
- private DescriptorService descriptorService;
- private TemplateProcessor templateProcessor;
- private FormatRegistry formatRegistry;
-
- //
- // Initialisation
- //
-
- /* (non-Javadoc)
- * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
- */
- public void setBeanName(String name)
- {
- this.name = name;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIContextAware#setAPIContext(javax.servlet.ServletContext)
- */
- public void setAPIContext(ServletContext context)
- {
- this.context = context;
- }
-
- /**
- * @param serviceRegistry
- */
- public void setServiceRegistry(ServiceRegistry serviceRegistry)
- {
- this.serviceRegistry = serviceRegistry;
- }
-
- /**
- * @param templateProcessor
- */
- public void setTemplateProcessor(TemplateProcessor templateProcessor)
- {
- this.templateProcessor = templateProcessor;
- }
-
- /**
- * @param descriptorService
- */
- public void setDescriptorService(DescriptorService descriptorService)
- {
- this.descriptorService = descriptorService;
- }
-
- /**
- * @param formatRegistry
- */
- public void setFormatRegistry(FormatRegistry formatRegistry)
- {
- this.formatRegistry = formatRegistry;
- }
-
- /**
- * Sets the Http URI
- *
- * @param uri
- */
- public void setHttpUri(String uri)
- {
- this.uri = uri;
- }
-
- //
- // Service Meta-Data
- //
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getName()
- */
- public String getName()
- {
- return this.name;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpUri()
- */
- public String getHttpUri()
- {
- return this.uri;
- }
-
-
- //
- // Service Implementation Helpers
- //
-
- /**
- * @return descriptorService
- */
- protected ServletContext getAPIContext()
- {
- return context;
- }
-
- /**
- * @return descriptorService
- */
- protected DescriptorService getDescriptorService()
- {
- return descriptorService;
- }
-
- /**
- * @return serviceRegistry
- */
- protected ServiceRegistry getServiceRegistry()
- {
- return serviceRegistry;
- }
-
- /**
- * @return templateProcessor
- */
- protected TemplateProcessor getTemplateProcessor()
- {
- return templateProcessor;
- }
-
- /**
- * @return formatRegistry
- */
- protected FormatRegistry getFormatRegistry()
- {
- return formatRegistry;
- }
-
-
- //
- // Basic Templating Support
- //
-
-
- /**
- * Create a basic API model
- *
- * @param req api request
- * @param res api response
- * @return template model
- */
- protected Map createAPIModel(APIRequest req, APIResponse res)
- {
- Map model = new HashMap(7, 1.0f);
- model.put("xmldate", new ISO8601DateFormatMethod());
- model.put("absurl", new AbsoluteUrlMethod(req.getPath()));
- model.put("urlencode", new UrlEncodeMethod());
- model.put("date", new Date());
- model.put("agent", descriptorService.getServerDescriptor());
- model.put("request", req);
- model.put("response", res);
- return model;
- }
-
- /**
- * Render a template (identified by path)
- *
- * @param templatePath template path
- * @param model model
- * @param writer output writer
- */
- protected void renderTemplate(String templatePath, Map model, Writer writer)
- {
- templateProcessor.process(templatePath, model, writer);
- }
-
- /**
- * Render a template (contents as string)
- * @param template the template
- * @param model model
- * @param writer output writer
- */
- protected void renderString(String template, Map model, Writer writer)
- {
- templateProcessor.processString(template, model, writer);
- }
-
-
- /**
- * Helper to retrieve API Service
- *
- * @param name name of service
- * @return the service
- */
- protected static APIService getMethod(String name)
- {
- String[] CONFIG_LOCATIONS = new String[] { "classpath:alfresco/application-context.xml", "classpath:alfresco/web-api-application-context.xml" };
- ApplicationContext context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS);
- APIService method = (APIService)context.getBean(name);
- return method;
- }
-
- /**
- * Create a base test model (for use stand-alone)
- *
- * @return test model
- */
- protected Map createTestModel()
- {
- Map model = new HashMap(7, 1.0f);
-
- // create api methods
- model.put("xmldate", new ISO8601DateFormatMethod());
- model.put("urlencode", new UrlEncodeMethod());
- model.put("absurl", new AbsoluteUrlMethod("http://test:8080/test"));
- model.put("date", new Date());
-
- // create dummy request model
- Map request = new HashMap();
- request.put("servicePath", "http://localhost:8080/alfresco/service");
- request.put("path", "http://localhost:8080/alfresco");
- request.put("url", "http://localhost:8080/alfresco/service/testurl");
- request.put("guest", false);
- request.put("format", "xml");
- model.put("request", request);
-
- // create dummy agent model
- model.put("agent", getDescriptorService().getServerDescriptor());
-
- return model;
- }
-
-}
diff --git a/source/java/org/alfresco/web/api/services/KeywordSearchDescription.java b/source/java/org/alfresco/web/api/services/Index.java
similarity index 52%
rename from source/java/org/alfresco/web/api/services/KeywordSearchDescription.java
rename to source/java/org/alfresco/web/api/services/Index.java
index fad1c95052..1ac4e4f372 100644
--- a/source/java/org/alfresco/web/api/services/KeywordSearchDescription.java
+++ b/source/java/org/alfresco/web/api/services/Index.java
@@ -1,94 +1,52 @@
-/*
- * 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.api.services;
-
-import java.util.Map;
-
-import org.alfresco.web.api.APIRequest;
-import org.alfresco.web.api.APIResponse;
-import org.alfresco.web.api.APIRequest.HttpMethod;
-import org.alfresco.web.api.APIRequest.RequiredAuthentication;
-
-
-/**
- * Provide OpenSearch Description for an Alfresco Keyword (simple) Search
- *
- * @author davidc
- */
-public class KeywordSearchDescription extends APIServiceTemplateImpl
-{
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getRequiredAuthentication()
- */
- public RequiredAuthentication getRequiredAuthentication()
- {
- return APIRequest.RequiredAuthentication.None;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpMethod()
- */
- public HttpMethod getHttpMethod()
- {
- return APIRequest.HttpMethod.GET;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDefaultFormat()
- */
- public String getDefaultFormat()
- {
- return APIResponse.OPENSEARCH_DESCRIPTION_FORMAT;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.services.APIServiceTemplateImpl#createModel(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse, java.util.Map)
- */
- @Override
- protected Map createModel(APIRequest req, APIResponse res, Map model)
- {
- return model;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDescription()
- */
- public String getDescription()
- {
- return "Retrieve the OpenSearch Description for the Alfresco Web Client keyword search";
- }
-
- /**
- * Simple test that can be executed outside of web context
- */
- public static void main(String[] args)
- throws Exception
- {
- KeywordSearchDescription service = (KeywordSearchDescription)APIServiceImpl.getMethod("web.api.KeywordSearchDescription");
- service.test(APIResponse.OPENSEARCH_DESCRIPTION_FORMAT);
- }
-
-}
+/*
+ * 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.api.services;
+
+import java.util.Map;
+
+import org.alfresco.web.api.APIRequest;
+import org.alfresco.web.api.APIResponse;
+import org.alfresco.web.api.ScriptedAPIService;
+
+
+/**
+ * Retrieves the list of available Web APIs
+ *
+ * @author davidc
+ */
+public class Index extends ScriptedAPIService
+{
+
+ /* (non-Javadoc)
+ * @see org.alfresco.web.api.services.APIServiceTemplateImpl#createModel(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse, java.util.Map)
+ */
+ @Override
+ protected Map createModel(APIRequest req, APIResponse res, Map model)
+ {
+ model.put("services", getAPIRegistry().getServices());
+ return model;
+ }
+
+}
diff --git a/source/java/org/alfresco/web/api/services/KeywordSearch.java b/source/java/org/alfresco/web/api/services/KeywordSearch.java
index c9aa116b1d..149372c58b 100644
--- a/source/java/org/alfresco/web/api/services/KeywordSearch.java
+++ b/source/java/org/alfresco/web/api/services/KeywordSearch.java
@@ -43,8 +43,7 @@ import org.alfresco.util.ParameterCheck;
import org.alfresco.web.api.APIException;
import org.alfresco.web.api.APIRequest;
import org.alfresco.web.api.APIResponse;
-import org.alfresco.web.api.APIRequest.HttpMethod;
-import org.alfresco.web.api.APIRequest.RequiredAuthentication;
+import org.alfresco.web.api.ScriptedAPIService;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -55,7 +54,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author davidc
*/
-public class KeywordSearch extends APIServiceTemplateImpl
+public class KeywordSearch extends ScriptedAPIService
{
// Logger
private static final Log logger = LogFactory.getLog(KeywordSearch.class);
@@ -64,7 +63,7 @@ public class KeywordSearch extends APIServiceTemplateImpl
// TODO: allow configuration of search store
protected static final StoreRef SEARCH_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
protected static final int DEFAULT_ITEMS_PER_PAGE = 10;
- protected static final String QUERY_TEMPLATE_TYPE = "query";
+ protected static final String QUERY_FORMAT = "query_";
// dependencies
protected SearchService searchService;
@@ -74,7 +73,7 @@ public class KeywordSearch extends APIServiceTemplateImpl
{
public String resolveImagePathForName(String filename, boolean small)
{
- return Utils.getFileTypeImage(getAPIContext(), filename, small);
+ return Utils.getFileTypeImage(getAPIRegistry().getContext(), filename, small);
}
};
@@ -86,38 +85,6 @@ public class KeywordSearch extends APIServiceTemplateImpl
this.searchService = searchService;
}
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getRequiredAuthentication()
- */
- public RequiredAuthentication getRequiredAuthentication()
- {
- return APIRequest.RequiredAuthentication.User;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpMethod()
- */
- public HttpMethod getHttpMethod()
- {
- return APIRequest.HttpMethod.GET;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDefaultFormat()
- */
- public String getDefaultFormat()
- {
- return APIResponse.HTML_FORMAT;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDescription()
- */
- public String getDescription()
- {
- return "Issue an Alfresco Web Client keyword search";
- }
-
/* (non-Javadoc)
* @see org.alfresco.web.api.services.APIServiceTemplateImpl#createModel(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse, java.util.Map)
*/
@@ -162,7 +129,7 @@ public class KeywordSearch extends APIServiceTemplateImpl
// execute the search
//
- SearchResult results = search(searchTerms, startPage, itemsPerPage, locale);
+ SearchResult results = search(searchTerms, startPage, itemsPerPage, locale, req.getParameterMap());
//
// append to model
@@ -181,7 +148,7 @@ public class KeywordSearch extends APIServiceTemplateImpl
* @param locale The current locale
* @return The search result
*/
- private SearchResult search(String searchTerms, int startPage, int itemsPerPage, Locale locale)
+ private SearchResult search(String searchTerms, int startPage, int itemsPerPage, Locale locale, Map reqParams)
{
SearchResult searchResult = null;
ResultSet results = null;
@@ -191,9 +158,10 @@ public class KeywordSearch extends APIServiceTemplateImpl
// construct search statement
String[] terms = searchTerms.split(" ");
Map statementModel = new HashMap(7, 1.0f);
+ statementModel.put("args", reqParams);
statementModel.put("terms", terms);
Writer queryWriter = new StringWriter(1024);
- renderTemplate(QUERY_TEMPLATE_TYPE, null, statementModel, queryWriter);
+ renderFormatTemplate(QUERY_FORMAT, statementModel, queryWriter);
String query = queryWriter.toString();
// execute query
@@ -411,28 +379,5 @@ public class KeywordSearch extends APIServiceTemplateImpl
return score;
}
}
-
-
- /**
- * Simple test that can be executed outside of web context
- */
- public static void main(String[] args)
- throws Exception
- {
- KeywordSearch service = (KeywordSearch)APIServiceImpl.getMethod("web.api.KeywordSearch");
- service.test(APIResponse.HTML_FORMAT);
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.services.APIServiceImpl#createTestModel()
- */
- @Override
- protected Map createTestModel()
- {
- Map model = super.createTestModel();
- SearchResult result = search("alfresco tutorial", 1, 5, I18NUtil.getLocale());
- model.put("search", result);
- return model;
- }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/api/services/SearchEngines.java b/source/java/org/alfresco/web/api/services/SearchEngines.java
index 166a3aad65..9a9d2abfb3 100644
--- a/source/java/org/alfresco/web/api/services/SearchEngines.java
+++ b/source/java/org/alfresco/web/api/services/SearchEngines.java
@@ -34,8 +34,7 @@ import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.web.api.APIRequest;
import org.alfresco.web.api.APIResponse;
-import org.alfresco.web.api.APIRequest.HttpMethod;
-import org.alfresco.web.api.APIRequest.RequiredAuthentication;
+import org.alfresco.web.api.ScriptedAPIService;
import org.alfresco.web.config.OpenSearchConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -46,7 +45,7 @@ import org.apache.commons.logging.LogFactory;
*
* @author davidc
*/
-public class SearchEngines extends APIServiceTemplateImpl
+public class SearchEngines extends ScriptedAPIService
{
// url argument values
public static final String URL_ARG_DESCRIPTION = "description";
@@ -76,38 +75,6 @@ public class SearchEngines extends APIServiceTemplateImpl
this.searchProxy = searchProxy;
}
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getRequiredAuthentication()
- */
- public RequiredAuthentication getRequiredAuthentication()
- {
- return APIRequest.RequiredAuthentication.None;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpMethod()
- */
- public HttpMethod getHttpMethod()
- {
- return APIRequest.HttpMethod.GET;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDefaultFormat()
- */
- public String getDefaultFormat()
- {
- return APIResponse.HTML_FORMAT;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDescription()
- */
- public String getDescription()
- {
- return "Retrieve a list of (server-side) registered search engines";
- }
-
@Override
protected Map createModel(APIRequest req, APIResponse res, Map model)
{
@@ -233,29 +200,5 @@ public class SearchEngines extends APIServiceTemplateImpl
return engine;
}
}
-
-
- /**
- * Simple test that can be executed outside of web context
- */
- public static void main(String[] args)
- throws Exception
- {
- SearchEngines service = (SearchEngines)APIServiceImpl.getMethod("web.api.SearchEngines");
- service.test(APIResponse.ATOM_FORMAT);
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.services.APIServiceImpl#createTestModel()
- */
- @Override
- protected Map createTestModel()
- {
- Map model = super.createTestModel();
- Set urls = getUrls(URL_ARG_ALL);
- model.put("urltype", "template");
- model.put("engines", urls);
- return model;
- }
-
+
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/web/api/services/SearchProxy.java b/source/java/org/alfresco/web/api/services/SearchProxy.java
index 760dea31df..7a9e79cdc7 100644
--- a/source/java/org/alfresco/web/api/services/SearchProxy.java
+++ b/source/java/org/alfresco/web/api/services/SearchProxy.java
@@ -41,9 +41,8 @@ import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.web.api.APIException;
import org.alfresco.web.api.APIRequest;
import org.alfresco.web.api.APIResponse;
+import org.alfresco.web.api.AbstractAPIService;
import org.alfresco.web.api.FormatRegistry;
-import org.alfresco.web.api.APIRequest.HttpMethod;
-import org.alfresco.web.api.APIRequest.RequiredAuthentication;
import org.alfresco.web.app.servlet.HTTPProxy;
import org.alfresco.web.config.OpenSearchConfigElement;
import org.alfresco.web.config.OpenSearchConfigElement.EngineConfig;
@@ -69,7 +68,7 @@ import org.springframework.beans.factory.InitializingBean;
*
* @author davidc
*/
-public class SearchProxy extends APIServiceImpl implements InitializingBean
+public class SearchProxy extends AbstractAPIService implements InitializingBean
{
// Logger
private static final Log logger = LogFactory.getLog(SearchProxy.class);
@@ -96,38 +95,6 @@ public class SearchProxy extends APIServiceImpl implements InitializingBean
this.configService = configService;
}
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getRequiredAuthentication()
- */
- public RequiredAuthentication getRequiredAuthentication()
- {
- return APIRequest.RequiredAuthentication.None;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpMethod()
- */
- public HttpMethod getHttpMethod()
- {
- return APIRequest.HttpMethod.GET;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDefaultFormat()
- */
- public String getDefaultFormat()
- {
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDescription()
- */
- public String getDescription()
- {
- return "Issue an OpenSearch query via Alfresco";
- }
-
/* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@@ -153,11 +120,11 @@ public class SearchProxy extends APIServiceImpl implements InitializingBean
public void execute(APIRequest req, APIResponse res)
throws IOException
{
- String extensionPath = req.getExtensionPath(this);
+ String extensionPath = req.getExtensionPath();
String[] extensionPaths = extensionPath.split("/");
if (extensionPaths.length != 2)
{
- throw new APIException("OpenSearch engine has not been specified as //");
+ throw new APIException("OpenSearch engine has not been specified as /{engine}/{format}");
}
// retrieve search engine configuration
diff --git a/source/java/org/alfresco/web/api/services/Services.java b/source/java/org/alfresco/web/api/services/Services.java
deleted file mode 100644
index ce1d732eaf..0000000000
--- a/source/java/org/alfresco/web/api/services/Services.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Alfresco Software Limited.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- * As a special exception to the terms and conditions of version 2.0 of
- * the GPL, you may redistribute this Program in connection with Free/Libre
- * and Open Source Software ("FLOSS") applications as described in Alfresco's
- * FLOSS exception. You should have recieved a copy of the text describing
- * the FLOSS exception, and it is also available here:
- * http://www.alfresco.com/legal/licensing"
- */
-package org.alfresco.web.api.services;
-
-import java.util.Collection;
-import java.util.Map;
-
-import org.alfresco.web.api.APIRequest;
-import org.alfresco.web.api.APIResponse;
-import org.alfresco.web.api.APIService;
-import org.alfresco.web.api.APIRequest.HttpMethod;
-import org.alfresco.web.api.APIRequest.RequiredAuthentication;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-
-
-/**
- * Retrieves the list of available Web APIs
- *
- * @author davidc
- */
-public class Services extends APIServiceTemplateImpl implements ApplicationContextAware
-{
- private ApplicationContext applicationContext;
-
-
- /* (non-Javadoc)
- * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
- */
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
- {
- this.applicationContext = applicationContext;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDescription()
- */
- public String getDescription()
- {
- return "Retrieve the list of available Alfresco Web APIs";
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getRequiredAuthentication()
- */
- public RequiredAuthentication getRequiredAuthentication()
- {
- return RequiredAuthentication.None;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getHttpMethod()
- */
- public HttpMethod getHttpMethod()
- {
- return HttpMethod.GET;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.APIService#getDefaultFormat()
- */
- public String getDefaultFormat()
- {
- return APIResponse.HTML_FORMAT;
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.services.APIServiceTemplateImpl#createModel(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse, java.util.Map)
- */
- @Override
- protected Map createModel(APIRequest req, APIResponse res, Map model)
- {
- model.put("services", getServices());
- return model;
- }
-
- /**
- * Gets the collection of API Services
- *
- * @return api services
- */
- private Collection getServices()
- {
- Map services = applicationContext.getBeansOfType(APIService.class, false, false);
- return services.values();
- }
-
-
- /**
- * Simple test that can be executed outside of web context
- */
- public static void main(String[] args)
- throws Exception
- {
- Services service = (Services)APIServiceImpl.getMethod("web.api.Services");
- service.test(APIResponse.HTML_FORMAT);
- }
-
- /* (non-Javadoc)
- * @see org.alfresco.web.api.services.APIServiceImpl#createTestModel()
- */
- @Override
- protected Map createTestModel()
- {
- Map model = super.createTestModel();
- model.put("services", getServices());
- return model;
- }
-
-}