From 257568270d6e4ab255cc01ef0c5cd7784ae7043b Mon Sep 17 00:00:00 2001 From: David Caruana Date: Wed, 20 Dec 2006 00:38:47 +0000 Subject: [PATCH] OpenSearch Impl - addition of icons (for search engine, feed and feed entries) - configurable items per page - addition of feed entry relevance (score) (ATOM only) - addition for generator & author feed elements (ATOM only) - guest url argument support - logging (log4j.logger.org.alfresco.web.api=DEBUG) - addition of abstract web api plug-in (for building new url web services) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4668 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../alfresco/web-api-application-context.xml | 17 +- .../java/org/alfresco/web/api/APIRequest.java | 25 +- .../org/alfresco/web/api/APIResponse.java | 2 +- ...erviceMap.java => APIServiceRegistry.java} | 38 ++- .../java/org/alfresco/web/api/APIServlet.java | 35 ++- ...ntication.java => BasicAuthenticator.java} | 38 ++- .../web/api/services/APIServiceImpl.java | 192 +++++++++++++++ .../alfresco/web/api/services/TextSearch.java | 232 +++++++++++------- .../api/services/TextSearchDescription.java | 53 +--- source/web/images/logo/AlfrescoLogo16.gif | Bin 0 -> 604 bytes source/web/images/logo/AlfrescoLogo16.ico | Bin 0 -> 894 bytes 11 files changed, 457 insertions(+), 175 deletions(-) rename source/java/org/alfresco/web/api/{APIServiceMap.java => APIServiceRegistry.java} (67%) rename source/java/org/alfresco/web/api/{BasicAuthentication.java => BasicAuthenticator.java} (72%) create mode 100644 source/java/org/alfresco/web/api/services/APIServiceImpl.java create mode 100644 source/web/images/logo/AlfrescoLogo16.gif create mode 100644 source/web/images/logo/AlfrescoLogo16.ico diff --git a/config/alfresco/web-api-application-context.xml b/config/alfresco/web-api-application-context.xml index 1d21a27c68..ea2b66a6af 100644 --- a/config/alfresco/web-api-application-context.xml +++ b/config/alfresco/web-api-application-context.xml @@ -8,9 +8,9 @@ - + - + @@ -19,16 +19,19 @@ - - + + + - + + + + + - - diff --git a/source/java/org/alfresco/web/api/APIRequest.java b/source/java/org/alfresco/web/api/APIRequest.java index 72f0868a0d..63a5e26f45 100644 --- a/source/java/org/alfresco/web/api/APIRequest.java +++ b/source/java/org/alfresco/web/api/APIRequest.java @@ -19,6 +19,8 @@ package org.alfresco.web.api; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import org.alfresco.repo.security.authentication.AuthenticationUtil; + /** * API Service Request @@ -47,13 +49,12 @@ public class APIRequest extends HttpServletRequestWrapper User } - /** * Construct * * @param req */ - public APIRequest(HttpServletRequest req) + /*package*/ APIRequest(HttpServletRequest req) { super(req); } @@ -89,4 +90,24 @@ public class APIRequest extends HttpServletRequestWrapper return getPath() + getServletPath(); } + /** + * Gets the currently authenticated username + * + * @return username + */ + public String getAuthenticatedUsername() + { + return AuthenticationUtil.getCurrentUserName(); + } + + /** + * Determine if Guest User? + * + * @return true => guest user + */ + public boolean isGuest() + { + return Boolean.valueOf(getParameter("guest")); + } + } diff --git a/source/java/org/alfresco/web/api/APIResponse.java b/source/java/org/alfresco/web/api/APIResponse.java index f89cc96d09..bef30a98ce 100644 --- a/source/java/org/alfresco/web/api/APIResponse.java +++ b/source/java/org/alfresco/web/api/APIResponse.java @@ -38,7 +38,7 @@ public class APIResponse extends HttpServletResponseWrapper * * @param res */ - public APIResponse(HttpServletResponse res) + /*package*/ APIResponse(HttpServletResponse res) { super(res); } diff --git a/source/java/org/alfresco/web/api/APIServiceMap.java b/source/java/org/alfresco/web/api/APIServiceRegistry.java similarity index 67% rename from source/java/org/alfresco/web/api/APIServiceMap.java rename to source/java/org/alfresco/web/api/APIServiceRegistry.java index 7701ba67ef..277fcbee41 100644 --- a/source/java/org/alfresco/web/api/APIServiceMap.java +++ b/source/java/org/alfresco/web/api/APIServiceRegistry.java @@ -20,8 +20,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import javax.servlet.ServletContext; + import org.aopalliance.intercept.MethodInterceptor; import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.RegexpMethodPointcutAdvisor; import org.springframework.context.ApplicationContext; @@ -30,7 +33,7 @@ import org.springframework.context.ApplicationContext; * * @author davidc */ -public class APIServiceMap +public class APIServiceRegistry { // TODO: Support different kinds of uri resolution (e.g. regex:/search/.*) @@ -44,17 +47,21 @@ public class APIServiceMap * * @param context */ - public APIServiceMap(ApplicationContext context) + public APIServiceRegistry(ServletContext servletContext, ApplicationContext appContext) { - // locate authentication interceptor - MethodInterceptor authInterceptor = (MethodInterceptor)context.getBean("web.api.Authentication"); - + // retrieve service authenticator + MethodInterceptor authenticator = (MethodInterceptor)appContext.getBean("web.api.Authenticator"); + // register all API Services - // NOTE: An API Service is one registered in Spring which supports the APIService interface - Map apiServices = context.getBeansOfType(APIService.class, false, false); + // NOTE: An API Service is one registered in Spring which is of type APIServiceImpl + Map apiServices = appContext.getBeansOfType(APIService.class, false, false); for (Map.Entry apiService : apiServices.entrySet()) { + // retrieve service APIService service = apiService.getValue(); + service.init(servletContext); + + // retrieve http method APIRequest.HttpMethod method = service.getHttpMethod(); String httpUri = service.getHttpUri(); if (httpUri == null || httpUri.length() == 0) @@ -62,14 +69,21 @@ public class APIServiceMap throw new APIException("Web API Service " + apiService.getKey() + " does not specify a HTTP URI mapping"); } - if (authInterceptor != null && service.getRequiredAuthentication() != APIRequest.RequiredAuthentication.None) + // wrap API Service in appropriate interceptors (e.g. authentication) + if (service.getRequiredAuthentication() != APIRequest.RequiredAuthentication.None) { - // wrap API Service in appropriate interceptors (e.g. authentication) - ProxyFactory authFactory = new ProxyFactory(service); - authFactory.addAdvice(authInterceptor); + if (authenticator == null) + { + throw new APIException("Web API Authenticator not specified"); + } + + RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(".*execute", authenticator); + ProxyFactory authFactory = new ProxyFactory((APIService)service); + authFactory.addAdvisor(advisor); service = (APIService)authFactory.getProxy(); } - + + // register service methods.add(method); uris.add(httpUri); services.add(service); diff --git a/source/java/org/alfresco/web/api/APIServlet.java b/source/java/org/alfresco/web/api/APIServlet.java index ed968bdc9e..a85f6fbee4 100644 --- a/source/java/org/alfresco/web/api/APIServlet.java +++ b/source/java/org/alfresco/web/api/APIServlet.java @@ -23,6 +23,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.alfresco.web.app.servlet.BaseServlet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; @@ -35,9 +37,12 @@ import org.springframework.web.context.support.WebApplicationContextUtils; public class APIServlet extends BaseServlet { private static final long serialVersionUID = 4209892938069597860L; - + + // Logger + private static final Log logger = LogFactory.getLog(APIServlet.class); + // API Services - private APIServiceMap apiServiceMap; + private APIServiceRegistry apiServiceRegistry; @Override @@ -47,18 +52,12 @@ public class APIServlet extends BaseServlet // Retrieve all web api services and index by http url & http method ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); - apiServiceMap = new APIServiceMap(context); + apiServiceRegistry = new APIServiceRegistry(getServletContext(), context); } // TODO: // - authentication (as suggested in http://www.xml.com/pub/a/2003/12/17/dive.html) -// - atom -// - generator -// - author (authenticated) -// - icon -// - html -// - icon /* @@ -80,16 +79,32 @@ public class APIServlet extends BaseServlet APIRequest.HttpMethod method = request.getHttpMethod(); String uri = request.getPathInfo(); - APIService service = apiServiceMap.get(method, uri); + if (logger.isDebugEnabled()) + logger.debug("Processing request (" + request.getHttpMethod() + ") " + request.getRequestURL() + (request.getQueryString() != null ? "?" + request.getQueryString() : "")); + + APIService service = apiServiceRegistry.get(method, uri); if (service != null) { + if (logger.isDebugEnabled()) + logger.debug("Mapped to service " + service.getName()); + + long start = System.currentTimeMillis(); service.execute(request, response); + long end = System.currentTimeMillis(); + + if (logger.isDebugEnabled()) + logger.debug("Service " + service.getName() + " executed in " + (end - start) + "ms"); } 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 } } diff --git a/source/java/org/alfresco/web/api/BasicAuthentication.java b/source/java/org/alfresco/web/api/BasicAuthenticator.java similarity index 72% rename from source/java/org/alfresco/web/api/BasicAuthentication.java rename to source/java/org/alfresco/web/api/BasicAuthenticator.java index 2470822696..f009d9747b 100644 --- a/source/java/org/alfresco/web/api/BasicAuthentication.java +++ b/source/java/org/alfresco/web/api/BasicAuthenticator.java @@ -22,6 +22,8 @@ import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.util.Base64; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** @@ -29,8 +31,11 @@ import org.aopalliance.intercept.MethodInvocation; * * @author davidc */ -public class BasicAuthentication implements MethodInterceptor +public class BasicAuthenticator implements MethodInterceptor { + // Logger + private static final Log logger = LogFactory.getLog(BasicAuthenticator.class); + // dependencies private AuthenticationService authenticationService; @@ -60,9 +65,22 @@ public class BasicAuthentication implements MethodInterceptor // validate credentials // + boolean isGuest = request.isGuest(); String authorization = request.getHeader("Authorization"); - if ((authorization == null || authorization.length() == 0) && service.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.Guest)) + + if (logger.isDebugEnabled()) { + logger.debug("Service authentication required: " + service.getRequiredAuthentication()); + logger.debug("Guest login: " + isGuest); + logger.debug("Authorization provided (overrides Guest login): " + (authorization != null && authorization.length() > 0)); + } + + if (((authorization == null || authorization.length() == 0) || isGuest) + && service.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.Guest)) + { + if (logger.isDebugEnabled()) + logger.debug("Authenticating as Guest"); + // authenticate as guest, if service allows authenticationService.authenticateAsGuest(); authorized = true; @@ -81,17 +99,26 @@ public class BasicAuthentication implements MethodInterceptor if (parts.length == 1) { + if (logger.isDebugEnabled()) + logger.debug("Authenticating ticket " + parts[0]); + // assume a ticket has been passed authenticationService.validate(parts[0]); authorized = true; } else { + if (logger.isDebugEnabled()) + logger.debug("Authenticating user " + parts[0]); + // assume username and password passed if (parts[0].equals(AuthenticationUtil.getGuestUserName())) { - authenticationService.authenticateAsGuest(); - authorized = true; + if (service.getRequiredAuthentication().equals(APIRequest.RequiredAuthentication.Guest)) + { + authenticationService.authenticateAsGuest(); + authorized = true; + } } else { @@ -110,6 +137,9 @@ public class BasicAuthentication implements MethodInterceptor // execute API service or request authorization // + if (logger.isDebugEnabled()) + logger.debug("Authenticated: " + authorized); + if (authorized) { retVal = invocation.proceed(); diff --git a/source/java/org/alfresco/web/api/services/APIServiceImpl.java b/source/java/org/alfresco/web/api/services/APIServiceImpl.java new file mode 100644 index 0000000000..185fffbef0 --- /dev/null +++ b/source/java/org/alfresco/web/api/services/APIServiceImpl.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.api.services; + +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.web.api.APIRequest; +import org.alfresco.web.api.APIResponse; +import org.alfresco.web.api.APIService; +import org.springframework.beans.factory.BeanNameAware; + + +/** + * Skeleton implementation of an API Service + * + * @author davidc + */ +public abstract class APIServiceImpl implements BeanNameAware, APIService +{ + private String name; + private String uri; + + // dependencies + private ServletContext context; + private ServiceRegistry serviceRegistry; + private DescriptorService descriptorService; + private TemplateService templateService; + + // + // Initialisation + // + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) + */ + public void setBeanName(String name) + { + this.name = name; + } + + /** + * @param serviceRegistry + */ + public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /** + * @param templateService + */ + public void setTemplateService(TemplateService templateService) + { + this.templateService = templateService; + } + + /** + * @param descriptorService + */ + public void setDescriptorService(DescriptorService descriptorService) + { + this.descriptorService = descriptorService; + } + + /* (non-Javadoc) + * @see org.alfresco.web.api.APIService#init(javax.servlet.ServletContext) + */ + public void init(ServletContext context) + { + this.context = context; + } + + /** + * 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 getServletContext() + { + return context; + } + + /** + * @return descriptorService + */ + protected DescriptorService getDescriptorService() + { + return descriptorService; + } + + /** + * @return serviceRegistry + */ + protected ServiceRegistry getServiceRegistry() + { + return serviceRegistry; + } + + /** + * @return templateService + */ + protected TemplateService getTemplateService() + { + return templateService; + } + + /** + * Create a basic template model + * + * @param req api request + * @param res api response + * @return template model + */ + protected Map createTemplateModel(APIRequest req, APIResponse res) + { + Map model = new HashMap(7, 1.0f); + model.put("date", new Date()); + model.put("agent", descriptorService.getServerDescriptor()); + model.put("request", req); + model.put("response", res); + return model; + } + + /** + * Render a template to the API Response + * + * @param template + * @param model + * @param res + */ + protected void renderTemplate(String template, Map model, APIResponse res) + throws IOException + { + templateService.processTemplateString(null, template, model, res.getWriter()); + } + +} diff --git a/source/java/org/alfresco/web/api/services/TextSearch.java b/source/java/org/alfresco/web/api/services/TextSearch.java index 7b119d49a9..ed4b50e072 100644 --- a/source/java/org/alfresco/web/api/services/TextSearch.java +++ b/source/java/org/alfresco/web/api/services/TextSearch.java @@ -19,23 +19,30 @@ package org.alfresco.web.api.services; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Date; import java.util.HashMap; import java.util.Map; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.cmr.repository.TemplateNode; import org.alfresco.service.cmr.repository.TemplateService; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.GUID; import org.alfresco.web.api.APIException; import org.alfresco.web.api.APIRequest; import org.alfresco.web.api.APIResponse; -import org.alfresco.web.api.APIService; +import org.alfresco.web.api.APIServlet; import org.alfresco.web.api.APIRequest.HttpMethod; import org.alfresco.web.api.APIRequest.RequiredAuthentication; +import org.alfresco.web.ui.common.Utils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; @@ -44,39 +51,27 @@ import org.springframework.context.ApplicationContext; * * @author davidc */ -public class TextSearch implements APIService +public class TextSearch extends APIServiceImpl { - // NOTE: startPage and startIndex are 1 offset. + // Logger + private static final Log logger = LogFactory.getLog(APIServlet.class); // search parameters - // TODO: allow configuration of these - private static final StoreRef searchStore = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); - private static final int itemsPerPage = 10; + // 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; // dependencies - private String uri; - private ServiceRegistry serviceRegistry; - private SearchService searchService; - private TemplateService templateService; + protected SearchService searchService; - - /** - * Sets the Http URI - * - * @param uri - */ - public void setHttpUri(String uri) + // icon resolver + protected TemplateImageResolver iconResolver = new TemplateImageResolver() { - this.uri = uri; - } - - /** - * @param serviceRegistry - */ - public void setServiceRegistry(ServiceRegistry serviceRegistry) - { - this.serviceRegistry = serviceRegistry; - } + public String resolveImagePathForName(String filename, boolean small) + { + return Utils.getFileTypeImage(getServletContext(), filename, small); + } + }; /** * @param searchService @@ -86,14 +81,6 @@ public class TextSearch implements APIService this.searchService = searchService; } - /** - * @param templateService - */ - public void setTemplateService(TemplateService templateService) - { - this.templateService = templateService; - } - /* (non-Javadoc) * @see org.alfresco.web.api.APIService#getRequiredAuthentication() */ @@ -110,14 +97,6 @@ public class TextSearch implements APIService return APIRequest.HttpMethod.GET; } - /* (non-Javadoc) - * @see org.alfresco.web.api.APIService#getHttpUri() - */ - public String getHttpUri() - { - return this.uri; - } - /* (non-Javadoc) * @see org.alfresco.web.api.APIService#execute(org.alfresco.web.api.APIRequest, org.alfresco.web.api.APIResponse) */ @@ -125,7 +104,7 @@ public class TextSearch implements APIService throws IOException { // - // execute the search + // process parameters // String searchTerms = req.getParameter("q"); @@ -139,8 +118,22 @@ public class TextSearch implements APIService { // NOTE: use default startPage } + String itemsPerPageArg = req.getParameter("c"); + int itemsPerPage = DEFAULT_ITEMS_PER_PAGE; + try + { + itemsPerPage = new Integer(itemsPerPageArg); + } + catch(NumberFormatException e) + { + // NOTE: use default itemsPerPage + } - SearchResult results = search(searchTerms, startPage); + // + // execute the search + // + + SearchResult results = search(searchTerms, startPage, itemsPerPage); // // render the results @@ -160,12 +153,10 @@ public class TextSearch implements APIService } } - // execute template - Map searchModel = new HashMap(7, 1.0f); - searchModel.put("request", req); - searchModel.put("search", results); + Map model = createTemplateModel(req, res); + model.put("search", results); res.setContentType(contentType + ";charset=UTF-8"); - templateService.processTemplateString(null, template, searchModel, res.getWriter()); + renderTemplate(template, model, res); } /** @@ -175,30 +166,38 @@ public class TextSearch implements APIService * @param startPage * @return */ - private SearchResult search(String searchTerms, int startPage) + private SearchResult search(String searchTerms, int startPage, int itemsPerPage) { SearchResult searchResult = null; ResultSet results = null; try { - // Construct search statement + // construct search statement String[] terms = searchTerms.split(" "); Map statementModel = new HashMap(7, 1.0f); statementModel.put("terms", terms); - String query = templateService.processTemplateString(null, QUERY_STATEMENT, statementModel); - results = searchService.query(searchStore, SearchService.LANGUAGE_LUCENE, query); - + String query = getTemplateService().processTemplateString(null, QUERY_STATEMENT, statementModel); + + // execute query + if (logger.isDebugEnabled()) + logger.debug("Issuing lucene search: " + query); + + results = searchService.query(SEARCH_STORE, SearchService.LANGUAGE_LUCENE, query); int totalResults = results.length(); - int totalPages = (totalResults / itemsPerPage); - totalPages += (totalResults % itemsPerPage != 0) ? 1 : 0; + + if (logger.isDebugEnabled()) + logger.debug("Results: " + totalResults + " rows"); // are we out-of-range + int totalPages = (totalResults / itemsPerPage); + totalPages += (totalResults % itemsPerPage != 0) ? 1 : 0; if (totalPages != 0 && (startPage < 1 || startPage > totalPages)) { throw new APIException("Start page " + startPage + " is outside boundary of " + totalPages + " pages"); } + // construct search result searchResult = new SearchResult(); searchResult.setSearchTerms(searchTerms); searchResult.setItemsPerPage(itemsPerPage); @@ -207,13 +206,14 @@ public class TextSearch implements APIService searchResult.setTotalResults(totalResults); searchResult.setStartIndex(((startPage -1) * itemsPerPage) + 1); searchResult.setTotalPageItems(Math.min(itemsPerPage, totalResults - searchResult.getStartIndex() + 1)); - TemplateNode[] nodes = new TemplateNode[searchResult.getTotalPageItems()]; + SearchTemplateNode[] nodes = new SearchTemplateNode[searchResult.getTotalPageItems()]; for (int i = 0; i < searchResult.getTotalPageItems(); i++) { - nodes[i] = new TemplateNode(results.getNodeRef(i + searchResult.getStartIndex() - 1), serviceRegistry, null); + NodeRef node = results.getNodeRef(i + searchResult.getStartIndex() - 1); + float score = results.getScore(i + searchResult.getStartIndex() - 1); + nodes[i] = new SearchTemplateNode(node, score); } searchResult.setResults(nodes); - return searchResult; } finally @@ -240,7 +240,7 @@ public class TextSearch implements APIService private int totalPageItems; private int startPage; private int startIndex; - private TemplateNode[] results; + private SearchTemplateNode[] results; public int getItemsPerPage() @@ -258,7 +258,7 @@ public class TextSearch implements APIService return results; } - /*package*/ void setResults(TemplateNode[] results) + /*package*/ void setResults(SearchTemplateNode[] results) { this.results = results; } @@ -333,41 +333,79 @@ public class TextSearch implements APIService } } + /** + * Search result row template node + */ + public class SearchTemplateNode extends TemplateNode + { + private static final long serialVersionUID = -1791913270786140012L; + private float score; + + /** + * Construct + * + * @param nodeRef + * @param score + */ + public SearchTemplateNode(NodeRef nodeRef, float score) + { + super(nodeRef, getServiceRegistry(), iconResolver); + this.score = score; + } + + /** + * Gets the result row score + * + * @return score + */ + public float getScore() + { + return score; + } + } + // TODO: place into accessible file private final static String ATOM_TEMPLATE = "<#assign dateformat=\"yyyy-MM-dd\">" + "<#assign timeformat=\"HH:mm:sszzz\">" + "\n" + - "\n" + + "\n" + + " Alfresco (${agent.edition})\n" + " Alfresco Search: ${search.searchTerms}\n" + - " 2003-12-13T18:30:02Z\n" + // TODO: + " ${date?string(dateformat)}T${date?string(timeformat)}\n" + + " ${request.path}/images/logo/AlfrescoLogo16.ico\n" + " \n" + - " Alfresco\n" + // TODO: Issuer of search? + " <#if request.authenticatedUsername?exists>${request.authenticatedUsername}<#else>unknown\n" + " \n" + " urn:uuid:${search.id}\n" + " ${search.totalResults}\n" + " ${search.startIndex}\n" + " ${search.itemsPerPage}\n" + " \n" + - " \n" + - " \n" + - " \n" + + " \n" + + " \n" + + " \n" + "<#if search.startPage > 1>" + - " \n" + + " \n" + "" + "<#if search.startPage < search.totalPages>" + - " \n" + + " \n" + "" + - " \n" + + " \n" + " \n" + "<#list search.results as row>" + " \n" + " ${row.name}\n" + - " \n" + + " \n" + + " ${request.path}${row.icon16}\"\n" + // TODO: Standard for entry icons? " urn:uuid:${row.id}\n" + " ${row.properties.modified?string(dateformat)}T${row.properties.modified?string(timeformat)}\n" + " ${row.properties.description}\n" + + " \n" + + " ${row.properties.creator}\n" + + " \n" + + " ${row.score}\n" + " \n" + "" + ""; @@ -386,53 +424,53 @@ public class TextSearch implements APIService " \n" + " \n" + "

Alfresco Text Search

\n" + - " Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms}.\n" + + " Results ${search.startIndex} - ${search.startIndex + search.totalPageItems - 1} of ${search.totalResults} for ${search.searchTerms} " + + "visible to user <#if request.authenticatedUsername?exists>${request.authenticatedUsername}<#else>unknown.\n" + " \n" + - " first" + + " first" + "<#if search.startPage > 1>" + - " previous" + + " previous" + "" + - " ${search.startPage}" + + " ${search.startPage}" + "<#if search.startPage < search.totalPages>" + - " next" + + " next" + "" + - " last" + + " last" + " \n" + "\n"; // TODO: place into accessible file private final static String QUERY_STATEMENT = - "( " + - " TYPE:\"{http://www.alfresco.org/model/content/1.0}content\" AND " + - " (" + - " (" + + "(" + + "TYPE:\"{http://www.alfresco.org/model/content/1.0}content\" AND " + + "(" + + "(" + "<#list 1..terms?size as i>" + - " @\\{http\\://www.alfresco.org/model/content/1.0\\}name:${terms[i - 1]}" + + "@\\{http\\://www.alfresco.org/model/content/1.0\\}name:${terms[i - 1]}" + "<#if (i < terms?size)>" + - " OR " + + " OR " + "" + "" + - " ) " + - " ( " + + ")" + + "(" + "<#list 1..terms?size as i>" + - " TEXT:${terms[i - 1]}" + + "TEXT:${terms[i - 1]}" + "<#if (i < terms?size)>" + - " OR " + + " OR " + "" + "" + - " )" + - " )" + + ")" + + ")" + ")"; @@ -453,6 +491,7 @@ public class TextSearch implements APIService method.setServiceRegistry((ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY)); method.setTemplateService((TemplateService)context.getBean(ServiceRegistry.TEMPLATE_SERVICE.getLocalName())); method.setSearchService((SearchService)context.getBean(ServiceRegistry.SEARCH_SERVICE.getLocalName())); + method.setDescriptorService((DescriptorService)context.getBean(ServiceRegistry.DESCRIPTOR_SERVICE.getLocalName())); method.setHttpUri("/search/text"); method.test(); } @@ -464,18 +503,21 @@ public class TextSearch implements APIService */ private void test() { - SearchResult result = search("alfresco tutorial", 1); + SearchResult result = search("alfresco tutorial", 1, 5); Map searchModel = new HashMap(7, 1.0f); Map request = new HashMap(); request.put("servicePath", "http://localhost:8080/alfresco/service"); request.put("path", "http://localhost:8080/alfresco"); + request.put("guest", false); + searchModel.put("date", new Date()); + searchModel.put("agent", getDescriptorService().getServerDescriptor()); searchModel.put("request", request); searchModel.put("search", result); StringWriter rendition = new StringWriter(); PrintWriter writer = new PrintWriter(rendition); - templateService.processTemplateString(null, HTML_TEMPLATE, searchModel, writer); + getTemplateService().processTemplateString(null, ATOM_TEMPLATE, searchModel, writer); System.out.println(rendition.toString()); } diff --git a/source/java/org/alfresco/web/api/services/TextSearchDescription.java b/source/java/org/alfresco/web/api/services/TextSearchDescription.java index 3da8ad77ec..44fd522c39 100644 --- a/source/java/org/alfresco/web/api/services/TextSearchDescription.java +++ b/source/java/org/alfresco/web/api/services/TextSearchDescription.java @@ -17,13 +17,10 @@ package org.alfresco.web.api.services; import java.io.IOException; -import java.util.HashMap; import java.util.Map; -import org.alfresco.service.cmr.repository.TemplateService; 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; @@ -33,30 +30,8 @@ import org.alfresco.web.api.APIRequest.RequiredAuthentication; * * @author davidc */ -public class TextSearchDescription implements APIService +public class TextSearchDescription extends APIServiceImpl { - // dependencies - private String uri; - private TemplateService templateService; - - /** - * Sets the Http URI - * - * @param uri - */ - public void setHttpUri(String uri) - { - this.uri = uri; - } - - /** - * @param templateService - */ - public void setTemplateService(TemplateService templateService) - { - this.templateService = templateService; - } - /* (non-Javadoc) * @see org.alfresco.web.api.APIService#getRequiredAuthentication() @@ -74,37 +49,27 @@ public class TextSearchDescription implements APIService return APIRequest.HttpMethod.GET; } - /* (non-Javadoc) - * @see org.alfresco.web.api.APIService#getHttpUri() - */ - public String getHttpUri() - { - return this.uri; - } - /* (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 { - // create model for open search template - Map model = new HashMap(7, 1.0f); - model.put("request", req); - - // execute template + Map model = createTemplateModel(req, res); res.setContentType(APIResponse.OPEN_SEARCH_DESCRIPTION_TYPE + ";charset=UTF-8"); - templateService.processTemplateString(null, OPEN_SEARCH_DESCRIPTION, model, res.getWriter()); + renderTemplate(OPEN_SEARCH_DESCRIPTION, model, res); } // TODO: place into accessible file private final static String OPEN_SEARCH_DESCRIPTION = "\n" + - "\n" + + "\n" + " Alfresco Text Search\n" + - " Search all of Alfresco Company Home via text keywords\n" + - " \n" + - " \n" + + " Alfresco ${agent.edition} Text Search ${agent.version}\n" + + " Search Alfresco \"company home\" using text keywords\n" + + " \n" + + " \n" + + " ${request.path}/images/logo/AlfrescoLogo16.ico\n" + ""; } diff --git a/source/web/images/logo/AlfrescoLogo16.gif b/source/web/images/logo/AlfrescoLogo16.gif new file mode 100644 index 0000000000000000000000000000000000000000..b38cabe39ff7d6fa7ca2f528f7ade60192a4455e GIT binary patch literal 604 zcmZ?wbhEHb6krfwc*Xz%|NsAI2>;Iz_n#r@KST0=hV1_g`TrS8|NGAS&rtDSw(UPd zL|p|69-f z?>+Zx_O<_;ANFM5M9V1 zHjhDO5rfP^2IZv;N{boPmNV$CW6)l~V6{%jaigr!Y6h$I44zw={r50+>vaVRMnbFVNCxB5#oQs2f1uq+8ps&9dqlEYsaZZjE>&3*xrPed5s;DW8-o9sV zrLD(kY{O`7VQncc&FJ`2o6+E%4x^^Nt`&#VqQmX`q~4`msF-@>_(TT73W+HPAD@^g m=f=ia*>ULDVPP#9uD~gR99-RuZ2~{dR&*RyT+hVFU=0AE>Ba5< literal 0 HcmV?d00001 diff --git a/source/web/images/logo/AlfrescoLogo16.ico b/source/web/images/logo/AlfrescoLogo16.ico new file mode 100644 index 0000000000000000000000000000000000000000..959e31fc932084d2175e25c37e55c58eb7a87ca4 GIT binary patch literal 894 zcmbu5K}b|l6o&tF5eSMI4lNuAg%U#vm#%D?B<&I+Vz3BdkSB=}xRP>cDFo3JJW(-6 zEG5*2A_T`VXrsZ53a$pGq-ZlJv>1%zf9BrzW}I1e-noZ!&i(#-&%3}me)aWWyo7;j zAON71i!EH{(!N?Z_sUHwEc82$>!}k@N#m3B0n#I_!&v;d1c$Soe{(LGzUe^6{ zfeb6c!4Ee~ekXnx(ORU!ED3n5EFK@2rt-7RNc6GPeEy2&h1u}^p&5Yv$GI(hxow%b zmWHJ+VwR6xV^U_ZTuS-Z7wFu=T#MzW8(9t|M=;$4H(<}-8fNo+(y@}6CY3C;TghT4 zmb>t=r+V!s2UE#HhZH2l%B(kv(A(O3v5Svp8|`24P00K1_R0w4KFWlqG!ogKQ2q&& zbUb+Ss)SXAgy35qnxGT zlF=Ox+