Merge Web Scripts from BRANCHES/DEV/DAVE

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5358 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2007-03-08 18:51:38 +00:00
parent 4b30804f20
commit 3bb7471045
37 changed files with 6464 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.scripts.bean;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
/**
* Retrieves the list of available Web APIs
*
* @author davidc
*/
public class Index extends DeclarativeWebScript
{
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, WebScriptResponse res)
{
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("webscripts", getWebScriptRegistry().getWebScripts());
return model;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.scripts.bean;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
/**
* Retrieves the list of available Web APIs
*
* @author davidc
*/
public class IndexUpdate extends DeclarativeWebScript
{
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, WebScriptResponse res)
{
List<String> tasks = new ArrayList<String>();
// reset index
String reset = req.getParameter("reset");
if (reset != null && reset.equals("on"))
{
int previousCount = getWebScriptRegistry().getWebScripts().size();
getWebScriptRegistry().reset();
tasks.add("Reset Web Scripts Registry; found " + getWebScriptRegistry().getWebScripts().size() + " Web Scripts. Previously, there were " + previousCount + ".");
}
// create model for rendering
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("tasks", tasks);
model.put("webscripts", getWebScriptRegistry().getWebScripts());
return model;
}
}

View File

@@ -0,0 +1,382 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.scripts.bean;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateNode;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.util.GUID;
import org.alfresco.util.ParameterCheck;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.alfresco.web.ui.common.Utils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Alfresco Keyword (simple) Search Service
*
* @author davidc
*/
public class KeywordSearch extends DeclarativeWebScript
{
// Logger
private static final Log logger = LogFactory.getLog(KeywordSearch.class);
// search parameters
// TODO: allow configuration of search store
protected static final StoreRef SEARCH_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore");
protected static final int DEFAULT_ITEMS_PER_PAGE = 10;
protected static final String QUERY_FORMAT = "query_";
// dependencies
protected SearchService searchService;
// icon resolver
protected TemplateImageResolver iconResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, boolean small)
{
return Utils.getFileTypeImage(getWebScriptRegistry().getContext(), filename, small);
}
};
/**
* @param searchService
*/
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, WebScriptResponse res)
{
//
// process arguments
//
String searchTerms = req.getParameter("q");
ParameterCheck.mandatoryString("q", searchTerms);
String startPageArg = req.getParameter("p");
int startPage = 1;
try
{
startPage = new Integer(startPageArg);
}
catch(NumberFormatException e)
{
// NOTE: use default startPage
}
String itemsPerPageArg = req.getParameter("c");
int itemsPerPage = DEFAULT_ITEMS_PER_PAGE;
try
{
itemsPerPage = new Integer(itemsPerPageArg);
}
catch(NumberFormatException e)
{
// NOTE: use default itemsPerPage
}
Locale locale = I18NUtil.getLocale();
String language = req.getParameter("l");
if (language != null && language.length() > 0)
{
// NOTE: Simple conversion from XML Language Id to Java Locale Id
locale = new Locale(language.replace("-", "_"));
}
//
// execute the search
//
SearchResult results = search(searchTerms, startPage, itemsPerPage, locale, req);
//
// create model
//
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("search", results);
return model;
}
/**
* Execute the search
*
* @param searchTerms
* @param startPage
* @return
*/
private SearchResult search(String searchTerms, int startPage, int itemsPerPage, Locale locale, WebScriptRequest req)
{
SearchResult searchResult = null;
ResultSet results = null;
try
{
// construct search statement
String[] terms = searchTerms.split(" ");
Map<String, Object> statementModel = new HashMap<String, Object>(7, 1.0f);
statementModel.put("args", createArgModel(req));
statementModel.put("terms", terms);
Writer queryWriter = new StringWriter(1024);
renderFormatTemplate(QUERY_FORMAT, statementModel, queryWriter);
String query = queryWriter.toString();
// execute query
if (logger.isDebugEnabled())
{
logger.debug("Search parameters: searchTerms=" + searchTerms + ", startPage=" + startPage + ", itemsPerPage=" + itemsPerPage + ", search locale=" + locale.toString());
logger.debug("Issuing lucene search: " + query);
}
SearchParameters parameters = new SearchParameters();
parameters.addStore(SEARCH_STORE);
parameters.setLanguage(SearchService.LANGUAGE_LUCENE);
parameters.setQuery(query);
if (locale != null)
{
parameters.addLocale(locale);
}
results = searchService.query(parameters);
int totalResults = results.length();
if (logger.isDebugEnabled())
logger.debug("Results: " + totalResults + " rows (limited: " + results.getResultSetMetaData().getLimitedBy() + ")");
// are we out-of-range
int totalPages = (totalResults / itemsPerPage);
totalPages += (totalResults % itemsPerPage != 0) ? 1 : 0;
if (totalPages != 0 && (startPage < 1 || startPage > totalPages))
{
throw new WebScriptException("Start page " + startPage + " is outside boundary of " + totalPages + " pages");
}
// construct search result
searchResult = new SearchResult();
searchResult.setSearchTerms(searchTerms);
searchResult.setLocale(locale);
searchResult.setItemsPerPage(itemsPerPage);
searchResult.setStartPage(startPage);
searchResult.setTotalPages(totalPages);
searchResult.setTotalResults(totalResults);
searchResult.setStartIndex(((startPage -1) * itemsPerPage) + 1);
searchResult.setTotalPageItems(Math.min(itemsPerPage, totalResults - searchResult.getStartIndex() + 1));
SearchTemplateNode[] nodes = new SearchTemplateNode[searchResult.getTotalPageItems()];
for (int i = 0; i < searchResult.getTotalPageItems(); i++)
{
NodeRef node = results.getNodeRef(i + searchResult.getStartIndex() - 1);
float score = results.getScore(i + searchResult.getStartIndex() - 1);
nodes[i] = new SearchTemplateNode(node, score);
}
searchResult.setResults(nodes);
return searchResult;
}
finally
{
if (results != null)
{
results.close();
}
}
}
/**
* Search Result
*
* @author davidc
*/
public static class SearchResult
{
private String id;
private String searchTerms;
private Locale locale;
private int itemsPerPage;
private int totalPages;
private int totalResults;
private int totalPageItems;
private int startPage;
private int startIndex;
private SearchTemplateNode[] results;
public int getItemsPerPage()
{
return itemsPerPage;
}
/*package*/ void setItemsPerPage(int itemsPerPage)
{
this.itemsPerPage = itemsPerPage;
}
public TemplateNode[] getResults()
{
return results;
}
/*package*/ void setResults(SearchTemplateNode[] results)
{
this.results = results;
}
public int getStartIndex()
{
return startIndex;
}
/*package*/ void setStartIndex(int startIndex)
{
this.startIndex = startIndex;
}
public int getStartPage()
{
return startPage;
}
/*package*/ void setStartPage(int startPage)
{
this.startPage = startPage;
}
public int getTotalPageItems()
{
return totalPageItems;
}
/*package*/ void setTotalPageItems(int totalPageItems)
{
this.totalPageItems = totalPageItems;
}
public int getTotalPages()
{
return totalPages;
}
/*package*/ void setTotalPages(int totalPages)
{
this.totalPages = totalPages;
}
public int getTotalResults()
{
return totalResults;
}
/*package*/ void setTotalResults(int totalResults)
{
this.totalResults = totalResults;
}
public String getSearchTerms()
{
return searchTerms;
}
/*package*/ void setSearchTerms(String searchTerms)
{
this.searchTerms = searchTerms;
}
public Locale getLocale()
{
return locale;
}
/**
* @return XML 1.0 Language Identification
*/
public String getLocaleId()
{
return locale.toString().replace('_', '-');
}
/*package*/ void setLocale(Locale locale)
{
this.locale = locale;
}
public String getId()
{
if (id == null)
{
id = GUID.generate();
}
return id;
}
}
/**
* Search result row template node
*/
public class SearchTemplateNode extends TemplateNode
{
private static final long serialVersionUID = -1791913270786140012L;
private float score;
/**
* Construct
*
* @param nodeRef
* @param score
*/
public SearchTemplateNode(NodeRef nodeRef, float score)
{
super(nodeRef, getServiceRegistry(), iconResolver);
this.score = score;
}
/**
* Gets the result row score
*
* @return score
*/
public float getScore()
{
return score;
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.scripts.bean;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.alfresco.config.Config;
import org.alfresco.config.ConfigService;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.web.config.OpenSearchConfigElement;
import org.alfresco.web.scripts.DeclarativeWebScript;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* List of (server-side) registered Search Engines
*
* @author davidc
*/
public class SearchEngines extends DeclarativeWebScript
{
// url argument values
public static final String URL_ARG_DESCRIPTION = "description";
public static final String URL_ARG_TEMPLATE = "template";
public static final String URL_ARG_ALL = "all";
// Logger
private static final Log logger = LogFactory.getLog(SearchEngines.class);
// dependencies
protected ConfigService configService;
protected SearchProxy searchProxy;
/**
* @param configService
*/
public void setConfigService(ConfigService configService)
{
this.configService = configService;
}
/**
* @param searchProxy
*/
public void setSearchProxy(SearchProxy searchProxy)
{
this.searchProxy = searchProxy;
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, WebScriptResponse res)
{
String urlType = req.getParameter("type");
if (urlType == null || urlType.length() == 0)
{
urlType = URL_ARG_DESCRIPTION;
}
else if (!urlType.equals(URL_ARG_DESCRIPTION) && !urlType.equals(URL_ARG_TEMPLATE) && !urlType.equals(URL_ARG_ALL))
{
urlType = URL_ARG_DESCRIPTION;
}
//
// retrieve open search engines configuration
//
Set<UrlTemplate> urls = getUrls(urlType);
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
model.put("urltype", urlType);
model.put("engines", urls);
return model;
}
/**
* Retrieve registered search engines
*
* @return set of search engines
*/
private Set<UrlTemplate> getUrls(String urlType)
{
if (logger.isDebugEnabled())
logger.debug("Search Engine parameters: urltype=" + urlType);
Set<UrlTemplate> urls = new HashSet<UrlTemplate>();
Config config = configService.getConfig("OpenSearch");
OpenSearchConfigElement searchConfig = (OpenSearchConfigElement)config.getConfigElement(OpenSearchConfigElement.CONFIG_ELEMENT_ID);
for (OpenSearchConfigElement.EngineConfig engineConfig : searchConfig.getEngines())
{
Map<String, String> engineUrls = engineConfig.getUrls();
for (Map.Entry<String, String> engineUrl : engineUrls.entrySet())
{
String type = engineUrl.getKey();
String url = searchProxy.createUrl(engineConfig, type);
if ((urlType.equals(URL_ARG_ALL)) ||
(urlType.equals(URL_ARG_DESCRIPTION) && type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)) ||
(urlType.equals(URL_ARG_TEMPLATE) && !type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION)))
{
String label = engineConfig.getLabel();
String labelId = engineConfig.getLabelId();
if (labelId != null && labelId.length() > 0)
{
String i18nLabel = I18NUtil.getMessage(labelId);
if (i18nLabel == null && label == null)
{
label = (i18nLabel == null) ? "$$" + labelId + "$$" : i18nLabel;
}
}
urls.add(new UrlTemplate(label, type, url));
}
// TODO: Extract URL templates from OpenSearch description
else if (urlType.equals(URL_ARG_TEMPLATE) &&
type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION))
{
}
}
}
if (logger.isDebugEnabled())
logger.debug("Retrieved " + urls.size() + " engine registrations");
return urls;
}
/**
* Model object for representing a registered search engine
*/
public static class UrlTemplate
{
private String type;
private String label;
private String url;
private UrlTemplate engine;
public UrlTemplate(String label, String type, String url)
{
this.label = label;
this.type = type;
this.url = url;
this.engine = null;
}
public UrlTemplate(String label, String type, String url, UrlTemplate engine)
{
this(label, type, url);
this.engine = engine;
}
public String getLabel()
{
return label;
}
public String getType()
{
return type;
}
public String getUrl()
{
return url;
}
public String getUrlType()
{
return (type.equals(MimetypeMap.MIMETYPE_OPENSEARCH_DESCRIPTION) ? "description" : "template");
}
public UrlTemplate getEngine()
{
return engine;
}
}
}

View File

@@ -0,0 +1,311 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.scripts.bean;
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.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.alfresco.web.scripts.AbstractWebScript;
import org.alfresco.web.scripts.FormatRegistry;
import org.alfresco.web.scripts.WebScriptException;
import org.alfresco.web.scripts.WebScriptRequest;
import org.alfresco.web.scripts.WebScriptResponse;
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 AbstractWebScript 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.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 WebScriptException("OpenSearch configuration not found");
}
ProxyConfig proxyConfig = searchConfig.getProxy();
if (proxyConfig == null)
{
throw new WebScriptException("OpenSearch proxy configuration not found");
}
proxyPath = proxyConfig.getUrl();
}
/* (non-Javadoc)
* @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
*/
public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException
{
String extensionPath = req.getExtensionPath();
String[] extensionPaths = extensionPath.split("/");
if (extensionPaths.length != 2)
{
throw new WebScriptException("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 WebScriptException("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 WebScriptException("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 WebScriptException("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.getServicePath() + "/" + req.getContextPath(), 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 WebScriptException("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;
}
}