mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
125605 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2) 125498 slanglois: MNT-16155 Update source headers - remove svn:eol-style property on Java and JSP source files git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@125783 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,91 +1,91 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.events.types.Event;
|
||||
import org.alfresco.events.types.RepositoryEventImpl;
|
||||
import org.alfresco.repo.events.EventPreparator;
|
||||
import org.alfresco.repo.events.EventPublisher;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Common code between Get based login and POST based login
|
||||
*/
|
||||
/* package scope */ abstract class AbstractLoginBean extends DeclarativeWebScript
|
||||
{
|
||||
// dependencies
|
||||
private AuthenticationService authenticationService;
|
||||
protected EventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* @param authenticationService AuthenticationService
|
||||
*/
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param eventPublisher EventPublisher
|
||||
*/
|
||||
public void setEventPublisher(EventPublisher eventPublisher)
|
||||
{
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
/* (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, Status status)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Map<String, Object> login(final String username, String password)
|
||||
{
|
||||
try
|
||||
{
|
||||
// get ticket
|
||||
authenticationService.authenticate(username, password.toCharArray());
|
||||
|
||||
eventPublisher.publishEvent(new EventPreparator(){
|
||||
@Override
|
||||
public Event prepareEvent(String user, String networkId, String transactionId)
|
||||
{
|
||||
// TODO need to fix up to pass correct seqNo and alfrescoClientId
|
||||
return new RepositoryEventImpl(-1l, "login", transactionId, networkId, new Date().getTime(),
|
||||
username, null);
|
||||
}
|
||||
});
|
||||
|
||||
// add ticket to model for javascript and template access
|
||||
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
|
||||
model.put("username", username);
|
||||
model.put("ticket", authenticationService.getCurrentTicket());
|
||||
|
||||
return model;
|
||||
}
|
||||
catch(AuthenticationException e)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed");
|
||||
}
|
||||
finally
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.events.types.Event;
|
||||
import org.alfresco.events.types.RepositoryEventImpl;
|
||||
import org.alfresco.repo.events.EventPreparator;
|
||||
import org.alfresco.repo.events.EventPublisher;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Common code between Get based login and POST based login
|
||||
*/
|
||||
/* package scope */ abstract class AbstractLoginBean extends DeclarativeWebScript
|
||||
{
|
||||
// dependencies
|
||||
private AuthenticationService authenticationService;
|
||||
protected EventPublisher eventPublisher;
|
||||
|
||||
/**
|
||||
* @param authenticationService AuthenticationService
|
||||
*/
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = authenticationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param eventPublisher EventPublisher
|
||||
*/
|
||||
public void setEventPublisher(EventPublisher eventPublisher)
|
||||
{
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
/* (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, Status status)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Map<String, Object> login(final String username, String password)
|
||||
{
|
||||
try
|
||||
{
|
||||
// get ticket
|
||||
authenticationService.authenticate(username, password.toCharArray());
|
||||
|
||||
eventPublisher.publishEvent(new EventPreparator(){
|
||||
@Override
|
||||
public Event prepareEvent(String user, String networkId, String transactionId)
|
||||
{
|
||||
// TODO need to fix up to pass correct seqNo and alfrescoClientId
|
||||
return new RepositoryEventImpl(-1l, "login", transactionId, networkId, new Date().getTime(),
|
||||
username, null);
|
||||
}
|
||||
});
|
||||
|
||||
// add ticket to model for javascript and template access
|
||||
Map<String, Object> model = new HashMap<String, Object>(7, 1.0f);
|
||||
model.put("username", username);
|
||||
model.put("ticket", authenticationService.getCurrentTicket());
|
||||
|
||||
return model;
|
||||
}
|
||||
catch(AuthenticationException e)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Login failed");
|
||||
}
|
||||
finally
|
||||
{
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,39 +1,39 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* WebScript java backed bean implementation - to return information about the
|
||||
* authentication system, such as account mutability.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class Authentication extends DeclarativeWebScript
|
||||
{
|
||||
private MutableAuthenticationService authenticationService;
|
||||
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = (MutableAuthenticationService)authenticationService;
|
||||
}
|
||||
|
||||
/* (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, Status status)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(2);
|
||||
|
||||
model.put("creationAllowed", this.authenticationService.isAuthenticationCreationAllowed());
|
||||
|
||||
return model;
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.cmr.security.AuthenticationService;
|
||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* WebScript java backed bean implementation - to return information about the
|
||||
* authentication system, such as account mutability.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class Authentication extends DeclarativeWebScript
|
||||
{
|
||||
private MutableAuthenticationService authenticationService;
|
||||
|
||||
public void setAuthenticationService(AuthenticationService authenticationService)
|
||||
{
|
||||
this.authenticationService = (MutableAuthenticationService)authenticationService;
|
||||
}
|
||||
|
||||
/* (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, Status status)
|
||||
{
|
||||
Map<String, Object> model = new HashMap<String, Object>(2);
|
||||
|
||||
model.put("creationAllowed", this.authenticationService.isAuthenticationCreationAllowed());
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -1,389 +1,389 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.repo.web.scripts.RepositoryImageResolver;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
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.SearchLanguageConversion;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
|
||||
/**
|
||||
* 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 ServiceRegistry serviceRegistry;
|
||||
protected RepositoryImageResolver imageResolver;
|
||||
protected SearchService searchService;
|
||||
protected NodeService nodeService;
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setRepositoryImageResolver(RepositoryImageResolver imageResolver)
|
||||
{
|
||||
this.imageResolver = imageResolver;
|
||||
}
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
//
|
||||
// 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
|
||||
*/
|
||||
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(" ");
|
||||
searchTerms = searchTerms.replaceAll("\"", """);
|
||||
|
||||
// Escape special characters in the terms, so that they can't confuse the parser
|
||||
for (int i=0; i<terms.length; i++)
|
||||
{
|
||||
terms[i] = SearchLanguageConversion.escapeLuceneQuery(terms[i]);
|
||||
}
|
||||
|
||||
Map<String, Object> statementModel = new HashMap<String, Object>(7, 1.0f);
|
||||
statementModel.put("args", createArgs(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.setTotalResults(totalResults);
|
||||
if (totalResults == 0)
|
||||
{
|
||||
searchResult.setTotalPages(0);
|
||||
searchResult.setStartIndex(0);
|
||||
searchResult.setTotalPageItems(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchResult.setTotalPages(totalPages);
|
||||
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);
|
||||
// Make the search resilient to invalid nodes
|
||||
if (!nodeService.exists(node))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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
|
||||
{
|
||||
protected final static String URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
private static final long serialVersionUID = -1791913270786140012L;
|
||||
private float score;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*/
|
||||
public SearchTemplateNode(NodeRef nodeRef, float score)
|
||||
{
|
||||
super(nodeRef, serviceRegistry, KeywordSearch.this.imageResolver.getImageResolver());
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result row score
|
||||
*/
|
||||
public float getScore()
|
||||
{
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl()
|
||||
{
|
||||
return MessageFormat.format(URL, new Object[] {
|
||||
getNodeRef().getStoreRef().getProtocol(),
|
||||
getNodeRef().getStoreRef().getIdentifier(),
|
||||
getNodeRef().getId(),
|
||||
URLEncoder.encode(getName()) } );
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.template.TemplateNode;
|
||||
import org.alfresco.repo.web.scripts.RepositoryImageResolver;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
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.SearchLanguageConversion;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||
import org.springframework.extensions.surf.util.URLEncoder;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
|
||||
/**
|
||||
* 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 ServiceRegistry serviceRegistry;
|
||||
protected RepositoryImageResolver imageResolver;
|
||||
protected SearchService searchService;
|
||||
protected NodeService nodeService;
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setRepositoryImageResolver(RepositoryImageResolver imageResolver)
|
||||
{
|
||||
this.imageResolver = imageResolver;
|
||||
}
|
||||
|
||||
public void setServiceRegistry(ServiceRegistry serviceRegistry)
|
||||
{
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
//
|
||||
// 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
|
||||
*/
|
||||
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(" ");
|
||||
searchTerms = searchTerms.replaceAll("\"", """);
|
||||
|
||||
// Escape special characters in the terms, so that they can't confuse the parser
|
||||
for (int i=0; i<terms.length; i++)
|
||||
{
|
||||
terms[i] = SearchLanguageConversion.escapeLuceneQuery(terms[i]);
|
||||
}
|
||||
|
||||
Map<String, Object> statementModel = new HashMap<String, Object>(7, 1.0f);
|
||||
statementModel.put("args", createArgs(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.setTotalResults(totalResults);
|
||||
if (totalResults == 0)
|
||||
{
|
||||
searchResult.setTotalPages(0);
|
||||
searchResult.setStartIndex(0);
|
||||
searchResult.setTotalPageItems(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchResult.setTotalPages(totalPages);
|
||||
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);
|
||||
// Make the search resilient to invalid nodes
|
||||
if (!nodeService.exists(node))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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
|
||||
{
|
||||
protected final static String URL = "/api/node/content/{0}/{1}/{2}/{3}";
|
||||
|
||||
private static final long serialVersionUID = -1791913270786140012L;
|
||||
private float score;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*/
|
||||
public SearchTemplateNode(NodeRef nodeRef, float score)
|
||||
{
|
||||
super(nodeRef, serviceRegistry, KeywordSearch.this.imageResolver.getImageResolver());
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result row score
|
||||
*/
|
||||
public float getScore()
|
||||
{
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl()
|
||||
{
|
||||
return MessageFormat.format(URL, new Object[] {
|
||||
getNodeRef().getStoreRef().getProtocol(),
|
||||
getNodeRef().getStoreRef().getIdentifier(),
|
||||
getNodeRef().getId(),
|
||||
URLEncoder.encode(getName()) } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,47 +1,47 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Login and establish a ticket
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class Login extends AbstractLoginBean
|
||||
{
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
// extract username and password
|
||||
String username = req.getParameter("u");
|
||||
if (username == null || username.length() == 0)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
|
||||
}
|
||||
String password = req.getParameter("pw");
|
||||
if (password == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return login(username, password);
|
||||
}
|
||||
catch(WebScriptException e)
|
||||
{
|
||||
status.setCode(e.getStatus());
|
||||
status.setMessage(e.getMessage());
|
||||
status.setRedirect(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Login and establish a ticket
|
||||
*
|
||||
* @author davidc
|
||||
*/
|
||||
public class Login extends AbstractLoginBean
|
||||
{
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
// extract username and password
|
||||
String username = req.getParameter("u");
|
||||
if (username == null || username.length() == 0)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
|
||||
}
|
||||
String password = req.getParameter("pw");
|
||||
if (password == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return login(username, password);
|
||||
}
|
||||
catch(WebScriptException e)
|
||||
{
|
||||
status.setCode(e.getStatus());
|
||||
status.setMessage(e.getMessage());
|
||||
status.setRedirect(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,75 +1,75 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.extensions.surf.util.Content;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Post based login script
|
||||
*/
|
||||
public class LoginPost extends AbstractLoginBean
|
||||
{
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
// Extract user and password from JSON POST
|
||||
Content c = req.getContent();
|
||||
if (c == null)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Missing POST body.");
|
||||
}
|
||||
|
||||
// TODO accept xml type.
|
||||
|
||||
// extract username and password from JSON object
|
||||
JSONObject json;
|
||||
try
|
||||
{
|
||||
json = new JSONObject(c.getContent());
|
||||
String username = json.getString("username");
|
||||
String password = json.getString("password");
|
||||
|
||||
if (username == null || username.length() == 0)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
|
||||
}
|
||||
|
||||
if (password == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return login(username, password);
|
||||
}
|
||||
catch(WebScriptException e)
|
||||
{
|
||||
status.setCode(e.getStatus());
|
||||
status.setMessage(e.getMessage());
|
||||
status.setRedirect(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (JSONException jErr)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"Unable to parse JSON POST body: " + jErr.getMessage());
|
||||
}
|
||||
catch (IOException ioErr)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
|
||||
"Unable to retrieve POST body: " + ioErr.getMessage());
|
||||
}
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.extensions.surf.util.Content;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Post based login script
|
||||
*/
|
||||
public class LoginPost extends AbstractLoginBean
|
||||
{
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
// Extract user and password from JSON POST
|
||||
Content c = req.getContent();
|
||||
if (c == null)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Missing POST body.");
|
||||
}
|
||||
|
||||
// TODO accept xml type.
|
||||
|
||||
// extract username and password from JSON object
|
||||
JSONObject json;
|
||||
try
|
||||
{
|
||||
json = new JSONObject(c.getContent());
|
||||
String username = json.getString("username");
|
||||
String password = json.getString("password");
|
||||
|
||||
if (username == null || username.length() == 0)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Username not specified");
|
||||
}
|
||||
|
||||
if (password == null)
|
||||
{
|
||||
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Password not specified");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return login(username, password);
|
||||
}
|
||||
catch(WebScriptException e)
|
||||
{
|
||||
status.setCode(e.getStatus());
|
||||
status.setMessage(e.getMessage());
|
||||
status.setRedirect(true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (JSONException jErr)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"Unable to parse JSON POST body: " + jErr.getMessage());
|
||||
}
|
||||
catch (IOException ioErr)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR,
|
||||
"Unable to retrieve POST body: " + ioErr.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,186 +1,186 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.extensions.config.Config;
|
||||
import org.springframework.extensions.config.ConfigService;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
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 ConfigService
|
||||
*/
|
||||
public void setConfigService(ConfigService configService)
|
||||
{
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchProxy 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)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.extensions.config.Config;
|
||||
import org.springframework.extensions.config.ConfigService;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
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 ConfigService
|
||||
*/
|
||||
public void setConfigService(ConfigService configService)
|
||||
{
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param searchProxy 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)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,317 +1,317 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig;
|
||||
import org.alfresco.web.app.servlet.HTTPProxy;
|
||||
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;
|
||||
import org.springframework.extensions.config.Config;
|
||||
import org.springframework.extensions.config.ConfigService;
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.FormatRegistry;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
|
||||
|
||||
|
||||
/**
|
||||
* 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 FormatRegistry
|
||||
*/
|
||||
public void setFormatRegistry(FormatRegistry formatRegistry)
|
||||
{
|
||||
this.formatRegistry = formatRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param configService 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
|
||||
// NOTE: This web script must be executed in a HTTP servlet environment
|
||||
if (!(res.getRuntime() instanceof WebScriptServletRuntime))
|
||||
{
|
||||
throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment");
|
||||
}
|
||||
|
||||
HttpServletResponse servletRes = WebScriptServletRuntime.getHttpServletResponse(res);
|
||||
SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServerPath() + req.getServiceContextPath(),
|
||||
engine, engineUrl, servletRes, Collections.singletonMap("User-Agent", req.getHeader("User-Agent")));
|
||||
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;
|
||||
private Map<String, String> headers;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param rootPath String
|
||||
* @param engine String
|
||||
* @param engineUrl String
|
||||
* @param response HttpServletResponse
|
||||
* @param headers request headers
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public SearchEngineHttpProxy(String rootPath, String engine, String engineUrl, HttpServletResponse response, Map<String, String> headers)
|
||||
throws MalformedURLException
|
||||
{
|
||||
super(engineUrl.startsWith("/") ? rootPath + engineUrl : engineUrl, response);
|
||||
this.engine = engine;
|
||||
this.rootPath = rootPath;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.app.servlet.HTTPProxy#setRequestHeaders(java.net.URLConnection)
|
||||
*/
|
||||
@Override
|
||||
protected void setRequestHeaders(URLConnection urlConnection)
|
||||
{
|
||||
if (headers != null)
|
||||
{
|
||||
for (Map.Entry<String, String> entry: headers.entrySet())
|
||||
{
|
||||
urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (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;
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.EngineConfig;
|
||||
import org.alfresco.repo.web.scripts.config.OpenSearchConfigElement.ProxyConfig;
|
||||
import org.alfresco.web.app.servlet.HTTPProxy;
|
||||
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;
|
||||
import org.springframework.extensions.config.Config;
|
||||
import org.springframework.extensions.config.ConfigService;
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.FormatRegistry;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.extensions.webscripts.servlet.WebScriptServletRuntime;
|
||||
|
||||
|
||||
/**
|
||||
* 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 FormatRegistry
|
||||
*/
|
||||
public void setFormatRegistry(FormatRegistry formatRegistry)
|
||||
{
|
||||
this.formatRegistry = formatRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param configService 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
|
||||
// NOTE: This web script must be executed in a HTTP servlet environment
|
||||
if (!(res.getRuntime() instanceof WebScriptServletRuntime))
|
||||
{
|
||||
throw new WebScriptException("Search Proxy must be executed in HTTP Servlet environment");
|
||||
}
|
||||
|
||||
HttpServletResponse servletRes = WebScriptServletRuntime.getHttpServletResponse(res);
|
||||
SearchEngineHttpProxy proxy = new SearchEngineHttpProxy(req.getServerPath() + req.getServiceContextPath(),
|
||||
engine, engineUrl, servletRes, Collections.singletonMap("User-Agent", req.getHeader("User-Agent")));
|
||||
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;
|
||||
private Map<String, String> headers;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param rootPath String
|
||||
* @param engine String
|
||||
* @param engineUrl String
|
||||
* @param response HttpServletResponse
|
||||
* @param headers request headers
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public SearchEngineHttpProxy(String rootPath, String engine, String engineUrl, HttpServletResponse response, Map<String, String> headers)
|
||||
throws MalformedURLException
|
||||
{
|
||||
super(engineUrl.startsWith("/") ? rootPath + engineUrl : engineUrl, response);
|
||||
this.engine = engine;
|
||||
this.rootPath = rootPath;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.alfresco.web.app.servlet.HTTPProxy#setRequestHeaders(java.net.URLConnection)
|
||||
*/
|
||||
@Override
|
||||
protected void setRequestHeaders(URLConnection urlConnection)
|
||||
{
|
||||
if (headers != null)
|
||||
{
|
||||
for (Map.Entry<String, String> entry: headers.entrySet())
|
||||
{
|
||||
urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (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;
|
||||
}
|
||||
}
|
@@ -1,26 +1,26 @@
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
|
||||
/**
|
||||
* WebScript java backed bean implementation - to simple return a STATUS_OK message
|
||||
* as a touch point for SSO authentication mechanisms on the web-tier. Such as NTLM.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class Touch extends AbstractWebScript
|
||||
{
|
||||
/* (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
|
||||
{
|
||||
res.setStatus(Status.STATUS_OK);
|
||||
res.getWriter().close();
|
||||
}
|
||||
package org.alfresco.repo.web.scripts.bean;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.extensions.webscripts.AbstractWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
|
||||
/**
|
||||
* WebScript java backed bean implementation - to simple return a STATUS_OK message
|
||||
* as a touch point for SSO authentication mechanisms on the web-tier. Such as NTLM.
|
||||
*
|
||||
* @author Kevin Roast
|
||||
*/
|
||||
public class Touch extends AbstractWebScript
|
||||
{
|
||||
/* (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
|
||||
{
|
||||
res.setStatus(Status.STATUS_OK);
|
||||
res.getWriter().close();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user