mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V2.0 to HEAD
svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V2.0@5118 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V2.0@5119 . - OpenSearch Proxy svn merge svn://svn.alfresco.com:3691/alfresco/BRANCHES/V2.0@5121 svn://svn.alfresco.com:3691/alfresco/BRANCHES/V2.0@5122 . - Extract sample OpenSearch engine registrations into extension config file. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5125 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
43
config/alfresco/extension/web-api-config-custom.xml.sample
Normal file
43
config/alfresco/extension/web-api-config-custom.xml.sample
Normal file
@@ -0,0 +1,43 @@
|
||||
<!-- -->
|
||||
<!-- Example configuration of multiple OpenSearch engines -->
|
||||
<!-- -->
|
||||
|
||||
<alfresco-config>
|
||||
|
||||
<config evaluator="string-compare" condition="OpenSearch">
|
||||
<opensearch>
|
||||
|
||||
<engines>
|
||||
|
||||
<!-- -->
|
||||
<!-- Example: Registration of remote Alfresco Server -->
|
||||
<!-- -->
|
||||
|
||||
<!-- TODO: Find/Replace [host] with server host name -->
|
||||
<!-- TODO: Find/Replace [port] with server port number -->
|
||||
|
||||
<engine label="Remote Alfresco Repository" proxy="remote">
|
||||
<url type="application/atom+xml">
|
||||
http://[host]:[port]/alfresco/service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest=true&format=atom
|
||||
</url>
|
||||
<url type="application/rss+xml">
|
||||
http://[host]:[port]/alfresco/service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest=true&format=rss
|
||||
</url>
|
||||
</engine>
|
||||
|
||||
<!-- -->
|
||||
<!-- Example: Registration of Alfresco's Open Talk Blog -->
|
||||
<!-- -->
|
||||
|
||||
<engine label="Alfresco Open Source Talk" proxy="opentalk">
|
||||
<url type="application/rss+xml">
|
||||
http://blogs.alfresco.com/opentalk/os-query?s={searchTerms}&itemstart={startIndex?}&itempage={startPage?}&itemlimit={count?}
|
||||
</url>
|
||||
</engine>
|
||||
|
||||
</engines>
|
||||
|
||||
</opensearch>
|
||||
</config>
|
||||
|
||||
</alfresco-config>
|
@@ -11,6 +11,7 @@
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<value>classpath:alfresco/web-api-config.xml</value>
|
||||
<value>classpath:alfresco/extension/web-api-config-custom.xml</value>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
@@ -136,6 +137,14 @@
|
||||
<bean id="web.api.SearchEngines" class="org.alfresco.web.api.services.SearchEngines" parent="web.api.APITemplateService">
|
||||
<property name="httpUri" value="/search/engines" />
|
||||
<property name="configService" ref="web.api.Config" />
|
||||
<property name="searchProxy" ref="web.api.SearchProxy" />
|
||||
</bean>
|
||||
|
||||
<!-- Alfresco (OpenSearch) Proxy -->
|
||||
<bean id="web.api.SearchProxy" class="org.alfresco.web.api.services.SearchProxy" parent="web.api.APIService">
|
||||
<property name="httpUri" value="/search/engine" />
|
||||
<property name="configService" ref="web.api.Config" />
|
||||
<property name="formatRegistry" ref="web.api.FormatRegistry" />
|
||||
</bean>
|
||||
|
||||
<!-- Alfresco Web Client Keyword Search Description (OpenSearch) -->
|
||||
|
@@ -10,10 +10,6 @@
|
||||
</element-readers>
|
||||
</plug-ins>
|
||||
|
||||
<config>
|
||||
<!-- TODO: host, port?? -->
|
||||
</config>
|
||||
|
||||
|
||||
<!-- -->
|
||||
<!-- Configuration of Open Search API -->
|
||||
@@ -21,7 +17,13 @@
|
||||
|
||||
<config evaluator="string-compare" condition="OpenSearch">
|
||||
<opensearch>
|
||||
|
||||
<engines>
|
||||
|
||||
<!-- -->
|
||||
<!-- Local Alfresco Repository -->
|
||||
<!-- -->
|
||||
|
||||
<engine label-id="current_repo" label="Alfresco Keyword Search">
|
||||
<url type="application/opensearchdescription+xml">
|
||||
/service/search/keywordsearchdescription.xml
|
||||
@@ -36,7 +38,14 @@
|
||||
/service/search/keyword?q={searchTerms}&p={startPage?}&c={count?}&l={language?}&guest={alf:guest?}
|
||||
</url>
|
||||
</engine>
|
||||
|
||||
</engines>
|
||||
|
||||
<proxy>
|
||||
<!-- URL of Search Engine proxy -->
|
||||
<url>/service/search/engine</url>
|
||||
</proxy>
|
||||
|
||||
</opensearch>
|
||||
</config>
|
||||
|
||||
|
@@ -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
|
||||
*
|
||||
|
@@ -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;
|
||||
|
@@ -34,7 +34,9 @@ public class FormatRegistry
|
||||
private static final Log logger = LogFactory.getLog(FormatRegistry.class);
|
||||
|
||||
private Map<String, String> formats;
|
||||
private Map<String, String> mimetypes;
|
||||
private Map<String, Map<String, String>> agentFormats;
|
||||
private Map<String, Map<String, String>> agentMimetypes;
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,7 +45,9 @@ public class FormatRegistry
|
||||
public FormatRegistry()
|
||||
{
|
||||
formats = new HashMap<String, String>();
|
||||
mimetypes = new HashMap<String, String>();
|
||||
agentFormats = new HashMap<String, Map<String, String>>();
|
||||
agentMimetypes = new HashMap<String, Map<String, String>>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,13 +60,16 @@ public class FormatRegistry
|
||||
{
|
||||
// retrieve formats list for agent
|
||||
Map<String, String> formatsForAgent = formats;
|
||||
Map<String, String> mimetypesForAgent = mimetypes;
|
||||
if (agent != null)
|
||||
{
|
||||
formatsForAgent = agentFormats.get(agent);
|
||||
if (formatsForAgent == null)
|
||||
{
|
||||
formatsForAgent = new HashMap<String, String>();
|
||||
mimetypesForAgent = new HashMap<String, String>();
|
||||
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 + ")");
|
||||
@@ -112,4 +120,32 @@ 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<String, String> mimetypesForAgent = agentMimetypes.get(agent);
|
||||
if (mimetypesForAgent != null)
|
||||
{
|
||||
format = mimetypesForAgent.get(mimetype);
|
||||
}
|
||||
}
|
||||
|
||||
if (format == null)
|
||||
{
|
||||
format = mimetypes.get(mimetype);
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<String, String> 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)) ||
|
||||
|
337
source/java/org/alfresco/web/api/services/SearchProxy.java
Normal file
337
source/java/org/alfresco/web/api/services/SearchProxy.java
Normal file
@@ -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 /<engine>/<format>");
|
||||
}
|
||||
|
||||
// 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<String, String> 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<String,String> uris = new HashMap<String,String>();
|
||||
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 <engine proxy="<name>">)
|
||||
* @param mimetype url to proxy (as identified by mimetype)
|
||||
* @return "proxied" url
|
||||
*/
|
||||
public String createUrl(OpenSearchConfigElement.EngineConfig engine, String mimetype)
|
||||
{
|
||||
Map<String, String> 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 <engine proxy="<name>">)
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
134
source/java/org/alfresco/web/app/servlet/HTTPProxy.java
Normal file
134
source/java/org/alfresco/web/app/servlet/HTTPProxy.java
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
119
source/java/org/alfresco/web/app/servlet/HTTPProxyServlet.java
Normal file
119
source/java/org/alfresco/web/app/servlet/HTTPProxyServlet.java
Normal file
@@ -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=<endpointUrl>[&<argName>=<argValue>]*
|
||||
*
|
||||
* 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<String, String[]> parameters = req.getParameterMap();
|
||||
for (Map.Entry<String, String[]> 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;
|
||||
}
|
||||
|
||||
}
|
@@ -37,7 +37,9 @@ public class OpenSearchConfigElement extends ConfigElementAdapter
|
||||
{
|
||||
public static final String CONFIG_ELEMENT_ID = "opensearch";
|
||||
|
||||
private ProxyConfig proxy;
|
||||
private Set<EngineConfig> engines = new HashSet<EngineConfig>(8, 10f);
|
||||
private Map<String, EngineConfig> enginesByProxy = new HashMap<String, EngineConfig>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -86,9 +88,36 @@ 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
|
||||
*/
|
||||
@@ -97,6 +126,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<String, String> urls = new HashMap<String, String>(8, 10f);
|
||||
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
@@ -135,6 +180,19 @@ public class OpenSearchConfigElement extends ConfigElementAdapter
|
||||
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,16 +237,38 @@ public class OpenSearchConfigElement extends ConfigElementAdapter
|
||||
this.urls.put(mimetype, uri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
* Inner class representing the configuration of the OpenSearch proxy
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
public static class ProxyConfig
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder(super.toString());
|
||||
buffer.append(" {label=").append(this.label);
|
||||
buffer.append(" labelId=").append(this.labelId).append(")");
|
||||
return buffer.toString();
|
||||
protected String url;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param url
|
||||
*/
|
||||
public ProxyConfig(String url)
|
||||
{
|
||||
if (url == null || url.length() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("'url' must be specified");
|
||||
}
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return url
|
||||
*/
|
||||
public String getUrl()
|
||||
{
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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<Element> 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;
|
||||
|
@@ -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<String, String> 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)
|
||||
|
@@ -246,6 +246,11 @@
|
||||
<servlet-class>org.alfresco.web.api.APIServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>proxyServlet</servlet-name>
|
||||
<servlet-class>org.alfresco.web.app.servlet.HTTPProxyServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>workflowDefinitionImageServlet</servlet-name>
|
||||
<servlet-class>org.alfresco.web.app.servlet.WorkflowDefinitionImageServlet</servlet-class>
|
||||
@@ -321,6 +326,11 @@
|
||||
<url-pattern>/service/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>proxyServlet</servlet-name>
|
||||
<url-pattern>/proxy</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>JBPMDeployProcessServlet</servlet-name>
|
||||
<url-pattern>/jbpm/deployprocess</url-pattern>
|
||||
|
Reference in New Issue
Block a user