mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merge Web Scripts from BRANCHES/DEV/DAVE
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5349 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
123
source/java/org/alfresco/web/api/APIDescription.java
Normal file
123
source/java/org/alfresco/web/api/APIDescription.java
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
142
source/java/org/alfresco/web/api/APIDescriptionImpl.java
Normal file
142
source/java/org/alfresco/web/api/APIDescriptionImpl.java
Normal file
@@ -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<String, URI> 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<String, URI>(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;
|
||||
}
|
||||
|
||||
}
|
30
source/java/org/alfresco/web/api/APIRegistry.java
Normal file
30
source/java/org/alfresco/web/api/APIRegistry.java
Normal file
@@ -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<APIService> getServices();
|
||||
|
||||
public FormatRegistry getFormatRegistry();
|
||||
|
||||
public APITemplateProcessor getTemplateProcessor();
|
||||
|
||||
//public APIScriptProcessor getScriptProcessor();
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
|
10
source/java/org/alfresco/web/api/APIServiceMatch.java
Normal file
10
source/java/org/alfresco/web/api/APIServiceMatch.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.alfresco.web.api;
|
||||
|
||||
public interface APIServiceMatch
|
||||
{
|
||||
|
||||
public String getPath();
|
||||
|
||||
public APIService getService();
|
||||
|
||||
}
|
@@ -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<APIRequest.HttpMethod> methods = new ArrayList<APIRequest.HttpMethod>();
|
||||
private List<String> uris = new ArrayList<String>();
|
||||
private List<APIService> services = new ArrayList<APIService>();
|
||||
|
||||
|
||||
/**
|
||||
* 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<String, APIService> apiServices = appContext.getBeansOfType(APIService.class, false, false);
|
||||
for (Map.Entry<String, APIService> 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;
|
||||
}
|
||||
|
||||
}
|
@@ -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");
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
22
source/java/org/alfresco/web/api/APIStore.java
Normal file
22
source/java/org/alfresco/web/api/APIStore.java
Normal file
@@ -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();
|
||||
}
|
||||
|
94
source/java/org/alfresco/web/api/APIStores.java
Normal file
94
source/java/org/alfresco/web/api/APIStores.java
Normal file
@@ -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<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
|
||||
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<APIStore> getAPIStores()
|
||||
{
|
||||
return applicationContext.getBeansOfType(APIStore.class, false, false).values();
|
||||
}
|
||||
|
||||
public void setTemplateProcessor(APITemplateProcessor templateProcessor)
|
||||
{
|
||||
this.templateProcessor = templateProcessor;
|
||||
}
|
||||
|
||||
public APITemplateProcessor getTemplateProcessor()
|
||||
{
|
||||
return templateProcessor;
|
||||
}
|
||||
|
||||
}
|
@@ -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<TemplateLoader> templateLoaders = new HashSet<TemplateLoader>();
|
||||
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());
|
||||
|
153
source/java/org/alfresco/web/api/AbstractAPIService.java
Normal file
153
source/java/org/alfresco/web/api/AbstractAPIService.java
Normal file
@@ -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<String, Object> createAPIModel(APIRequest req, APIResponse res)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(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<String, Object> 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<String, Object> model, Writer writer)
|
||||
{
|
||||
getAPIRegistry().getTemplateProcessor().processString(template, model, writer);
|
||||
}
|
||||
|
||||
}
|
@@ -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");
|
||||
|
@@ -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;
|
||||
|
116
source/java/org/alfresco/web/api/ClassPathAPIStore.java
Normal file
116
source/java/org/alfresco/web/api/ClassPathAPIStore.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
454
source/java/org/alfresco/web/api/DeclarativeAPIRegistry.java
Normal file
454
source/java/org/alfresco/web/api/DeclarativeAPIRegistry.java
Normal file
@@ -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<String, APIService> servicesById = new TreeMap<String, APIService>();
|
||||
|
||||
// map of services by url
|
||||
// NOTE: The map is sorted by url (descending order)
|
||||
private Map<String, APIService> servicesByURL = new TreeMap<String, APIService>(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 <servicedescription> 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 <name>_<method>_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 <shortname> 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 <url> element");
|
||||
}
|
||||
List<APIDescription.URI> uris = new ArrayList<APIDescription.URI>();
|
||||
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 <url> 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 <authentication> 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<String, APIService> 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<APIService> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
10
source/java/org/alfresco/web/api/ScriptLoader.java
Normal file
10
source/java/org/alfresco/web/api/ScriptLoader.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.alfresco.web.api;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ScriptLocation;
|
||||
|
||||
public interface ScriptLoader
|
||||
{
|
||||
|
||||
ScriptLocation getScriptLocation(String path);
|
||||
|
||||
}
|
@@ -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<String, Object> 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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> 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<String, Object> 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<Object>()
|
||||
{
|
||||
public Object doWork()
|
||||
{
|
||||
// create test model
|
||||
Map<String, Object> 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<String, Object> 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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> 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<String, Object> 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);
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
{
|
||||
|
94
source/java/org/alfresco/web/api/SystemAuthenticator.java
Normal file
94
source/java/org/alfresco/web/api/SystemAuthenticator.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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<String> 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<String> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
214
source/java/org/alfresco/web/api/TestAPIServer.java
Normal file
214
source/java/org/alfresco/web/api/TestAPIServer.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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<String, Object> createAPIModel(APIRequest req, APIResponse res)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(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<String, Object> 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<String, Object> 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<String, Object> createTestModel()
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(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<String, Object> request = new HashMap<String, Object>();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@@ -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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> 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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> model)
|
||||
{
|
||||
model.put("services", getAPIRegistry().getServices());
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@@ -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<String, Object> statementModel = new HashMap<String, Object>(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<String, Object> createTestModel()
|
||||
{
|
||||
Map<String, Object> model = super.createTestModel();
|
||||
SearchResult result = search("alfresco tutorial", 1, 5, I18NUtil.getLocale());
|
||||
model.put("search", result);
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@@ -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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> 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<String, Object> createTestModel()
|
||||
{
|
||||
Map<String, Object> model = super.createTestModel();
|
||||
Set<UrlTemplate> urls = getUrls(URL_ARG_ALL);
|
||||
model.put("urltype", "template");
|
||||
model.put("engines", urls);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -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 /<engine>/<format>");
|
||||
throw new APIException("OpenSearch engine has not been specified as /{engine}/{format}");
|
||||
}
|
||||
|
||||
// retrieve search engine configuration
|
||||
|
@@ -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<String, Object> createModel(APIRequest req, APIResponse res, Map<String, Object> model)
|
||||
{
|
||||
model.put("services", getServices());
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of API Services
|
||||
*
|
||||
* @return api services
|
||||
*/
|
||||
private Collection<APIService> getServices()
|
||||
{
|
||||
Map<String, APIService> 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<String, Object> createTestModel()
|
||||
{
|
||||
Map<String, Object> model = super.createTestModel();
|
||||
model.put("services", getServices());
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user