diff --git a/config/alfresco/extension/web-api-config-custom.xml.sample b/config/alfresco/extension/web-api-config-custom.xml.sample new file mode 100644 index 0000000000..a74cad5da7 --- /dev/null +++ b/config/alfresco/extension/web-api-config-custom.xml.sample @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + http://[host]:[port]/alfresco/service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest=true&format=atom + + + http://[host]:[port]/alfresco/service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest=true&format=rss + + + + + + + + + + http://blogs.alfresco.com/opentalk/os-query?s={searchTerms}&itemstart={startIndex?}&itempage={startPage?}&itemlimit={count?} + + + + + + + + + diff --git a/config/alfresco/web-api-application-context.xml b/config/alfresco/web-api-application-context.xml index bb2df4714e..ee1e6cbeb2 100644 --- a/config/alfresco/web-api-application-context.xml +++ b/config/alfresco/web-api-application-context.xml @@ -11,6 +11,7 @@ classpath:alfresco/web-api-config.xml + classpath:alfresco/extension/web-api-config-custom.xml @@ -136,8 +137,16 @@ + + + + + + + + @@ -148,5 +157,5 @@ - + diff --git a/config/alfresco/web-api-config.xml b/config/alfresco/web-api-config.xml index 1c5da46223..76ddfafad7 100644 --- a/config/alfresco/web-api-config.xml +++ b/config/alfresco/web-api-config.xml @@ -10,18 +10,20 @@ - - - - - + - + + + + + + + /service/search/keywordsearchdescription.xml @@ -36,7 +38,14 @@ /service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?} + + + + + /service/search/engine + + diff --git a/source/java/org/alfresco/web/api/APIRequest.java b/source/java/org/alfresco/web/api/APIRequest.java index 7c28a20f38..c7da7f91e1 100644 --- a/source/java/org/alfresco/web/api/APIRequest.java +++ b/source/java/org/alfresco/web/api/APIRequest.java @@ -91,6 +91,29 @@ public class APIRequest extends HttpServletRequestWrapper return getPath() + getServletPath(); } + /** + * Gets the path extension beyond the path registered for this service + * + * e.g. + * a) service registered path = /search/engine + * b) request path = /search/engine/external + * + * => /external + * + * @return extension path + */ + public String getExtensionPath(APIService service) + { + String servicePath = service.getHttpUri(); + String extensionPath = getPathInfo(); + int extIdx = extensionPath.indexOf(servicePath); + if (extIdx != -1) + { + extensionPath = extensionPath.substring(extIdx + servicePath.length() + 1 /* exclude leading / */); + } + return extensionPath; + } + /** * Gets the full request URL * diff --git a/source/java/org/alfresco/web/api/APIServiceRegistry.java b/source/java/org/alfresco/web/api/APIServiceRegistry.java index 6ba029d63f..3c1cc032a0 100644 --- a/source/java/org/alfresco/web/api/APIServiceRegistry.java +++ b/source/java/org/alfresco/web/api/APIServiceRegistry.java @@ -116,7 +116,7 @@ public class APIServiceRegistry // TODO: Replace with more efficient approach for (int i = 0; i < services.size(); i++) { - if (methods.get(i).equals(method) && uris.get(i).equals(uri)) + if (methods.get(i).equals(method) && uri.startsWith(uris.get(i))) { apiService = services.get(i); break; diff --git a/source/java/org/alfresco/web/api/FormatRegistry.java b/source/java/org/alfresco/web/api/FormatRegistry.java index 03df935f35..f2caeb7467 100644 --- a/source/java/org/alfresco/web/api/FormatRegistry.java +++ b/source/java/org/alfresco/web/api/FormatRegistry.java @@ -34,7 +34,9 @@ public class FormatRegistry private static final Log logger = LogFactory.getLog(FormatRegistry.class); private Map formats; + private Map mimetypes; private Map> agentFormats; + private Map> agentMimetypes; /** @@ -43,7 +45,9 @@ public class FormatRegistry public FormatRegistry() { formats = new HashMap(); + mimetypes = new HashMap(); agentFormats = new HashMap>(); + agentMimetypes = new HashMap>(); } /** @@ -56,13 +60,16 @@ public class FormatRegistry { // retrieve formats list for agent Map formatsForAgent = formats; + Map mimetypesForAgent = mimetypes; if (agent != null) { formatsForAgent = agentFormats.get(agent); if (formatsForAgent == null) { formatsForAgent = new HashMap(); + mimetypesForAgent = new HashMap(); agentFormats.put(agent, formatsForAgent); + agentMimetypes.put(agent, mimetypesForAgent); } } @@ -78,6 +85,7 @@ public class FormatRegistry } formatsForAgent.put(entry.getKey(), entry.getValue()); + mimetypesForAgent.put(entry.getValue(), entry.getKey()); if (logger.isDebugEnabled()) logger.debug("Registered API format '" + entry.getKey() + "' with mime type '" + entry.getValue() + "' (agent: " + agent + ")"); @@ -111,5 +119,33 @@ public class FormatRegistry return mimetype; } - + + /** + * Gets the format for the specified user agent and mimetype + * + * @param agent + * @param mimetype + * @return format (or null, if one is not registered) + */ + public String getFormat(String agent, String mimetype) + { + String format = null; + + if (agent != null) + { + Map mimetypesForAgent = agentMimetypes.get(agent); + if (mimetypesForAgent != null) + { + format = mimetypesForAgent.get(mimetype); + } + } + + if (format == null) + { + format = mimetypes.get(mimetype); + } + + return format; + } + } diff --git a/source/java/org/alfresco/web/api/services/SearchEngines.java b/source/java/org/alfresco/web/api/services/SearchEngines.java index 8120a1fb7c..da92e96a29 100644 --- a/source/java/org/alfresco/web/api/services/SearchEngines.java +++ b/source/java/org/alfresco/web/api/services/SearchEngines.java @@ -51,6 +51,7 @@ public class SearchEngines extends APIServiceTemplateImpl // dependencies protected ConfigService configService; + protected SearchProxy searchProxy; /** * @param configService @@ -60,6 +61,14 @@ public class SearchEngines extends APIServiceTemplateImpl this.configService = configService; } + /** + * @param searchProxy + */ + public void setSearchProxy(SearchProxy searchProxy) + { + this.searchProxy = searchProxy; + } + /* (non-Javadoc) * @see org.alfresco.web.api.APIService#getRequiredAuthentication() */ @@ -135,7 +144,7 @@ public class SearchEngines extends APIServiceTemplateImpl for (Map.Entry engineUrl : engineUrls.entrySet()) { String type = engineUrl.getKey(); - String url = engineUrl.getValue(); + String url = searchProxy.createUrl(engineConfig, type); if ((urlType.equals(URL_ARG_ALL)) || (urlType.equals(URL_ARG_DESCRIPTION) && type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) || diff --git a/source/java/org/alfresco/web/api/services/SearchProxy.java b/source/java/org/alfresco/web/api/services/SearchProxy.java new file mode 100644 index 0000000000..7db966201e --- /dev/null +++ b/source/java/org/alfresco/web/api/services/SearchProxy.java @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * 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. + */ +package org.alfresco.web.api.services; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.alfresco.config.Config; +import org.alfresco.config.ConfigService; +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.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; +import org.alfresco.web.config.OpenSearchConfigElement.ProxyConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.XPath; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; +import org.springframework.beans.factory.InitializingBean; + + +/** + * Alfresco OpenSearch Proxy Service + * + * Provides the ability to submit a request to a registered search engine + * via the Alfresco server. + * + * @author davidc + */ +public class SearchProxy extends APIServiceImpl implements InitializingBean +{ + // Logger + private static final Log logger = LogFactory.getLog(SearchProxy.class); + + // dependencies + protected FormatRegistry formatRegistry; + protected ConfigService configService; + protected OpenSearchConfigElement searchConfig; + protected String proxyPath; + + /** + * @param formatRegistry + */ + public void setFormatRegistry(FormatRegistry formatRegistry) + { + this.formatRegistry = formatRegistry; + } + + /** + * @param configService + */ + public void setConfigService(ConfigService configService) + { + 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() + */ + public void afterPropertiesSet() throws Exception + { + Config config = configService.getConfig("OpenSearch"); + searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID); + if (searchConfig == null) + { + throw new APIException("OpenSearch configuration not found"); + } + ProxyConfig proxyConfig = searchConfig.getProxy(); + if (proxyConfig == null) + { + throw new APIException("OpenSearch proxy configuration not found"); + } + proxyPath = proxyConfig.getUrl(); + } + + /* (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 + { + String extensionPath = req.getExtensionPath(this); + String[] extensionPaths = extensionPath.split("/"); + if (extensionPaths.length != 2) + { + throw new APIException("OpenSearch engine has not been specified as //"); + } + + // retrieve search engine configuration + String engine = extensionPaths[0]; + EngineConfig engineConfig = searchConfig.getEngine(engine); + if (engineConfig == null) + { + throw new APIException("OpenSearch engine '" + engine + "' does not exist"); + } + + // retrieve engine url as specified by format + String format = extensionPaths[1]; + String mimetype = formatRegistry.getMimeType(null, format); + if (mimetype == null) + { + throw new APIException("Format '" + format + "' does not map to a registered mimetype"); + } + Map engineUrls = engineConfig.getUrls(); + String engineUrl = engineUrls.get(mimetype); + if (engineUrl == null) + { + throw new APIException("Url mimetype '" + mimetype + "' does not exist for engine '" + engine + "'"); + } + + // replace template url arguments with actual arguments specified on request + int engineUrlArgIdx = engineUrl.indexOf("?"); + if (engineUrlArgIdx != -1) + { + engineUrl = engineUrl.substring(0, engineUrlArgIdx); + } + if (req.getQueryString() != null) + { + engineUrl += "?" + req.getQueryString(); + } + + if (logger.isDebugEnabled()) + logger.debug("Mapping engine '" + engine + "' (mimetype '" + mimetype + "') to url '" + engineUrl + "'"); + + // issue request against search engine + SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getPath(), engine, engineUrl, res); + proxy.service(); + } + + /** + * OpenSearch HTTPProxy + * + * This proxy remaps OpenSearch links (e.g. previous, next) found in search results. + * + * @author davidc + */ + private class SearchEngineHttpProxy extends HTTPProxy + { + private final static String ATOM_NS_URI = "http://www.w3.org/2005/Atom"; + private final static String ATOM_NS_PREFIX = "atom"; + private final static String ATOM_LINK_XPATH = "atom:link[@rel=\"first\" or @rel=\"last\" or @rel=\"next\" or @rel=\"previous\" or @rel=\"self\" or @rel=\"alternate\"]"; + private String engine; + private String rootPath; + + /** + * Construct + * + * @param requestUrl + * @param response + * @throws MalformedURLException + */ + public SearchEngineHttpProxy(String rootPath, String engine, String engineUrl, HttpServletResponse response) + throws MalformedURLException + { + super(engineUrl.startsWith("/") ? rootPath + engineUrl : engineUrl, response); + this.engine = engine; + this.rootPath = rootPath; + } + + /* (non-Javadoc) + * @see org.alfresco.web.app.servlet.HTTPProxy#writeResponse(java.io.InputStream, java.io.OutputStream) + */ + @Override + protected void writeResponse(InputStream input, OutputStream output) + throws IOException + { + if (response.getContentType().startsWith(MimetypeMap.MIMETYPE_ATOM) || + response.getContentType().startsWith(MimetypeMap.MIMETYPE_RSS)) + { + // Only post-process ATOM and RSS feeds + // Replace all navigation links with "proxied" versions + SAXReader reader = new SAXReader(); + try + { + Document document = reader.read(input); + Element rootElement = document.getRootElement(); + + XPath xpath = rootElement.createXPath(ATOM_LINK_XPATH); + Map uris = new HashMap(); + uris.put(ATOM_NS_PREFIX, ATOM_NS_URI); + xpath.setNamespaceURIs(uris); + + List nodes = xpath.selectNodes(rootElement); + Iterator iter = nodes.iterator(); + while (iter.hasNext()) + { + Element element = (Element)iter.next(); + Attribute hrefAttr = element.attribute("href"); + String mimetype = element.attributeValue("type"); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_HTML; + } + String url = createUrl(engine, hrefAttr.getValue(), mimetype); + if (url.startsWith("/")) + { + url = rootPath + url; + } + hrefAttr.setValue(url); + } + + OutputFormat outputFormat = OutputFormat.createPrettyPrint(); + XMLWriter writer = new XMLWriter(output, outputFormat); + writer.write(rootElement); + writer.flush(); + } + catch(DocumentException e) + { + throw new IOException(e.toString()); + } + } + else + { + super.writeResponse(input, output); + } + } + } + + /** + * Construct a "proxied" search engine url + * + * @param engine engine name (as identified by ) + * @param mimetype url to proxy (as identified by mimetype) + * @return "proxied" url + */ + public String createUrl(OpenSearchConfigElement.EngineConfig engine, String mimetype) + { + Map urls = engine.getUrls(); + String url = urls.get(mimetype); + if (url != null) + { + String proxy = engine.getProxy(); + if (proxy != null && !mimetype.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) + { + url = createUrl(proxy, url, mimetype); + } + } + return url; + } + + /** + * Construct a "proxied" search engine url + * + * @param engine engine name (as identified by ) + * @param url engine url + * @param mimetype mimetype of url + * @return "proxied" url + */ + public String createUrl(String engine, String url, String mimetype) + { + String format = formatRegistry.getFormat(null, mimetype); + if (format == null) + { + throw new APIException("Mimetype '" + mimetype + "' is not registered."); + } + + String proxyUrl = null; + int argIdx = url.indexOf("?"); + if (argIdx == -1) + { + proxyUrl = proxyPath + "/" + engine + "/" + format; + } + else + { + proxyUrl = proxyPath + "/" + engine + "/" + format + url.substring(argIdx); + } + return proxyUrl; + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/web/app/servlet/HTTPProxy.java b/source/java/org/alfresco/web/app/servlet/HTTPProxy.java new file mode 100644 index 0000000000..db8e274ad0 --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/HTTPProxy.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * 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. + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import javax.servlet.http.HttpServletResponse; + + +/** + * Simple server-side HTTP Request / Response + * + * @author davidc + */ +public class HTTPProxy +{ + protected URL url; + protected HttpServletResponse response; + + + /** + * Construct + * + * @param requestUrl url to request + * @param response response to write request back to + * @throws MalformedURLException + */ + public HTTPProxy(String requestUrl, HttpServletResponse response) + throws MalformedURLException + { + this.url = new URL(requestUrl); + this.response = response; + } + + /** + * Perform request + * + * @throws IOException + */ + public void service() + throws IOException + { + URLConnection connection = url.openConnection(); + initialiseResponse(connection); + InputStream input = connection.getInputStream(); + OutputStream output = response.getOutputStream(); + try + { + writeResponse(input, output); + } + finally + { + try + { + if (input != null) + { + input.close(); + } + if (output != null) + { + output.flush(); + output.close(); + } + } + catch(IOException e) + { + } + } + } + + /** + * Initialise response + * + * @param urlConnection url connection + */ + protected void initialiseResponse(URLConnection urlConnection) + { + String type = urlConnection.getContentType(); + if (type != null) + { + int encodingIdx = type.lastIndexOf("charset="); + if (encodingIdx == -1) + { + String encoding = urlConnection.getContentEncoding(); + if (encoding != null && encoding.length() > 0) + { + type += ";charset=" + encoding; + } + } + + response.setContentType(type); + } + } + + /** + * Write response + * + * @param input input stream of request + * @param output output stream of response + * @throws IOException + */ + protected void writeResponse(InputStream input, OutputStream output) + throws IOException + { + byte[] buffer = new byte[1024]; + int read = input.read(buffer); + while (read != -1) + { + output.write(buffer, 0, read); + read = input.read(buffer); + } + } + +} diff --git a/source/java/org/alfresco/web/app/servlet/HTTPProxyServlet.java b/source/java/org/alfresco/web/app/servlet/HTTPProxyServlet.java new file mode 100644 index 0000000000..9ffe63482f --- /dev/null +++ b/source/java/org/alfresco/web/app/servlet/HTTPProxyServlet.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * 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. + */ +package org.alfresco.web.app.servlet; + +import java.io.IOException; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * HTTP Proxy Servlet + * + * Provides the ability to submit a URL request via the Alfresco Server i.e. + * the Alfresco server acts as a proxy. + * + * This servlet accepts: + * + * /proxy?endpoint=[&=]* + * + * Where: + * + * - endpointUrl is the URL to make a request against + * - argName is the name of a URL argument to append to the request + * - argValue is the value of URL argument + * + * E.g.: + * + * /proxy?endpoint=http://www.alfresco.com&arg1=value1&arg2=value2 + * + * @author davidc + */ +public class HTTPProxyServlet extends BaseServlet +{ + private static final long serialVersionUID = -576405943603122206L; + + /** + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + protected void doGet(HttpServletRequest req, HttpServletResponse res) + throws ServletException, IOException + { + String endpoint = null; + String args = null; + + Map parameters = req.getParameterMap(); + for (Map.Entry parameter : parameters.entrySet()) + { + String[] values = parameter.getValue(); + int startIdx = 0; + + if (parameter.getKey().equals("endpoint") && values.length > 0) + { + endpoint = values[0]; + startIdx++; + } + + for (int i = startIdx; i < values.length; i++) + { + String arg = parameter.getKey() + "=" + values[i]; + args = (args == null) ? arg : args + "&" + arg; + } + } + + if (endpoint == null || endpoint.length() == 0) + { + throw new IllegalArgumentException("endpoint argument not specified"); + } + + String url = endpoint + ((args == null) ? "" : "?" + args); + HTTPProxy proxy = new HTTPProxy(url, res); + proxy.service(); + } + + /** + * Construct a "proxied" URL + * + * Note: the "proxied" URL is a relative url + * + * @param url the URL to proxy + * @return the "proxied" url + */ + public static String createProxyUrl(String url) + { + String proxy = "/proxy"; + if (url != null && url.length() > 0) + { + int argIndex = url.lastIndexOf("?"); + if (argIndex == -1) + { + proxy += "?endpoint=" + url; + } + else + { + proxy += "?endpoint=" + url.substring(0, argIndex) + "&" + url.substring(argIndex + 1); + } + } + + return proxy; + } + +} diff --git a/source/java/org/alfresco/web/config/OpenSearchConfigElement.java b/source/java/org/alfresco/web/config/OpenSearchConfigElement.java index 65afe06768..76b54ac3d2 100644 --- a/source/java/org/alfresco/web/config/OpenSearchConfigElement.java +++ b/source/java/org/alfresco/web/config/OpenSearchConfigElement.java @@ -37,8 +37,10 @@ public class OpenSearchConfigElement extends ConfigElementAdapter { public static final String CONFIG_ELEMENT_ID = "opensearch"; + private ProxyConfig proxy; private Set engines = new HashSet(8, 10f); - + private Map enginesByProxy = new HashMap(); + /** * Default constructor @@ -85,10 +87,37 @@ public class OpenSearchConfigElement extends ConfigElementAdapter { combinedElement.addEngine(plugin); } + + // set the proxy configuration + ProxyConfig proxyConfig = this.getProxy(); + if (proxyConfig != null) + { + combinedElement.setProxy(proxyConfig); + } return combinedElement; } + /** + * Sets the proxy configuration + * + * @param proxyConfig + */ + /*package*/ void setProxy(ProxyConfig proxyConfig) + { + this.proxy = proxyConfig; + } + + /** + * Gets the proxy configuration + * + * @return + */ + public ProxyConfig getProxy() + { + return this.proxy; + } + /** * @return Returns a set of the engines */ @@ -96,6 +125,15 @@ public class OpenSearchConfigElement extends ConfigElementAdapter { return this.engines; } + + /** + * @param proxy name of engine proxy + * @return associated engine config (or null, if none registered against proxy) + */ + public EngineConfig getEngine(String proxy) + { + return this.enginesByProxy.get(proxy); + } /** * Adds an engine @@ -105,6 +143,11 @@ public class OpenSearchConfigElement extends ConfigElementAdapter /*package*/ void addEngine(EngineConfig engineConfig) { this.engines.add(engineConfig); + String proxy = engineConfig.getProxy(); + if (proxy != null && proxy.length() > 0) + { + this.enginesByProxy.put(proxy, engineConfig); + } } @@ -117,8 +160,10 @@ public class OpenSearchConfigElement extends ConfigElementAdapter { protected String label; protected String labelId; + protected String proxy; protected Map urls = new HashMap(8, 10f); + /** * Construct * @@ -134,7 +179,20 @@ public class OpenSearchConfigElement extends ConfigElementAdapter this.label = label; this.labelId = labelId; } - + + /** + * Construct + * + * @param label + * @param labelId + * @param proxy + */ + public EngineConfig(String label, String labelId, String proxy) + { + this(label, labelId); + this.proxy = proxy; + } + /** * @return I18N label id */ @@ -151,6 +209,14 @@ public class OpenSearchConfigElement extends ConfigElementAdapter return label; } + /** + * @return proxy + */ + public String getProxy() + { + return proxy; + } + /** * Gets the urls supported by this engine * @@ -171,17 +237,39 @@ public class OpenSearchConfigElement extends ConfigElementAdapter this.urls.put(mimetype, uri); } + } + + + /** + * Inner class representing the configuration of the OpenSearch proxy + * + * @author davidc + */ + public static class ProxyConfig + { + protected String url; + /** - * @see java.lang.Object#toString() + * Construct + * + * @param url */ - @Override - public String toString() + public ProxyConfig(String url) { - StringBuilder buffer = new StringBuilder(super.toString()); - buffer.append(" {label=").append(this.label); - buffer.append(" labelId=").append(this.labelId).append(")"); - return buffer.toString(); - } + if (url == null || url.length() == 0) + { + throw new IllegalArgumentException("'url' must be specified"); + } + this.url = url; + } + + /** + * @return url + */ + public String getUrl() + { + return url; + } } } diff --git a/source/java/org/alfresco/web/config/OpenSearchElementReader.java b/source/java/org/alfresco/web/config/OpenSearchElementReader.java index 18a177af3c..4009bf6ec9 100644 --- a/source/java/org/alfresco/web/config/OpenSearchElementReader.java +++ b/source/java/org/alfresco/web/config/OpenSearchElementReader.java @@ -23,6 +23,7 @@ import org.alfresco.config.ConfigElement; import org.alfresco.config.ConfigException; import org.alfresco.config.xml.elementreader.ConfigElementReader; import org.alfresco.web.config.OpenSearchConfigElement.EngineConfig; +import org.alfresco.web.config.OpenSearchConfigElement.ProxyConfig; import org.dom4j.Element; @@ -37,9 +38,11 @@ public class OpenSearchElementReader implements ConfigElementReader public static final String ELEMENT_ENGINES = "engines"; public static final String ELEMENT_ENGINE = "engine"; public static final String ELEMENT_URL = "url"; + public static final String ELEMENT_PROXY = "proxy"; public static final String ATTR_TYPE = "type"; public static final String ATTR_LABEL = "label"; public static final String ATTR_LABEL_ID = "label-id"; + public static final String ATTR_PROXY = "proxy"; /** @@ -71,7 +74,8 @@ public class OpenSearchElementReader implements ConfigElementReader Element engineElem = engines.next(); String label = engineElem.attributeValue(ATTR_LABEL); String labelId = engineElem.attributeValue(ATTR_LABEL_ID); - EngineConfig engineCfg = new EngineConfig(label, labelId); + String proxy = engineElem.attributeValue(ATTR_PROXY); + EngineConfig engineCfg = new EngineConfig(label, labelId, proxy); // construct urls for engine Iterator urlsConfig = engineElem.elementIterator(ELEMENT_URL); @@ -87,6 +91,20 @@ public class OpenSearchElementReader implements ConfigElementReader configElement.addEngine(engineCfg); } } + + // extract proxy configuration + String url = null; + Element proxyElem = element.element(ELEMENT_PROXY); + if (proxyElem != null) + { + Element urlElem = proxyElem.element(ELEMENT_URL); + if (urlElem != null) + { + url = urlElem.getTextTrim(); + ProxyConfig proxyCfg = new ProxyConfig(url); + configElement.setProxy(proxyCfg); + } + } } return configElement; diff --git a/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java b/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java index 2d05f304f8..774c531909 100644 --- a/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java +++ b/source/java/org/alfresco/web/ui/repo/component/UIOpenSearch.java @@ -12,6 +12,7 @@ import javax.faces.context.ResponseWriter; import org.alfresco.config.Config; import org.alfresco.config.ConfigService; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.web.api.services.SearchProxy; import org.alfresco.web.app.Application; import org.alfresco.web.config.OpenSearchConfigElement; import org.alfresco.web.config.OpenSearchConfigElement.EngineConfig; @@ -28,7 +29,6 @@ import org.springframework.web.jsf.FacesContextUtils; public class UIOpenSearch extends SelfRenderingComponent { protected final static String SCRIPTS_WRITTEN = "_alfOpenSearchScripts"; - protected final static String ATOM_TYPE = "application/atom+xml"; protected final static String ENGINE_ID_PREFIX = "eng"; // ------------------------------------------------------------------------------ @@ -205,6 +205,8 @@ public class UIOpenSearch extends SelfRenderingComponent // get the web api config service object from spring ConfigService cfgSvc = (ConfigService)FacesContextUtils. getRequiredWebApplicationContext(context).getBean("web.api.Config"); + SearchProxy searchProxy = (SearchProxy)FacesContextUtils. + getRequiredWebApplicationContext(context).getBean("web.api.SearchProxy"); if (cfgSvc != null) { // get the OpenSearch configuration @@ -229,11 +231,10 @@ public class UIOpenSearch extends SelfRenderingComponent } // locate search engine template url of most appropriate response type - Map urls = engineCfg.getUrls(); - String url = urls.get(MimetypeMap.MIMETYPE_ATOM); + String url = searchProxy.createUrl(engineCfg, MimetypeMap.MIMETYPE_ATOM); if (url == null) { - url = urls.get(MimetypeMap.MIMETYPE_RSS); + url = searchProxy.createUrl(engineCfg, MimetypeMap.MIMETYPE_RSS); } if (url != null) diff --git a/source/web/WEB-INF/web.xml b/source/web/WEB-INF/web.xml index 929ccf287f..53ad676644 100644 --- a/source/web/WEB-INF/web.xml +++ b/source/web/WEB-INF/web.xml @@ -245,6 +245,11 @@ apiServlet org.alfresco.web.api.APIServlet + + + proxyServlet + org.alfresco.web.app.servlet.HTTPProxyServlet + workflowDefinitionImageServlet @@ -321,6 +326,11 @@ /service/* + + proxyServlet + /proxy + + JBPMDeployProcessServlet /jbpm/deployprocess