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