/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/component/service/impl/BaseSearchServiceImpl.java $
* $Id: BaseSearchServiceImpl.java 118402 2013-01-16 21:32:11Z jbush@rsmart.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.search.component.service.impl;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermFreqVector;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Version;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationEdit;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.search.api.InvalidSearchQueryException;
import org.sakaiproject.search.api.SearchIndexBuilder;
import org.sakaiproject.search.api.SearchList;
import org.sakaiproject.search.api.SearchResult;
import org.sakaiproject.search.api.SearchService;
import org.sakaiproject.search.api.SearchStatus;
import org.sakaiproject.search.api.TermFrequency;
import org.sakaiproject.search.component.Messages;
import org.sakaiproject.search.filter.SearchItemFilter;
import org.sakaiproject.search.index.IndexReloadListener;
import org.sakaiproject.search.index.IndexStorage;
import org.sakaiproject.search.journal.impl.JournalSettings;
import org.sakaiproject.search.model.SearchBuilderItem;
import org.sakaiproject.search.util.DidYouMeanParser;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
/**
* The search service
*
* @author ieb
*/
public abstract class BaseSearchServiceImpl implements SearchService
{
private static Log log = LogFactory.getLog(BaseSearchServiceImpl.class);
/**
* The index builder dependency
*/
private SearchIndexBuilder searchIndexBuilder;
/**
* dependency
*/
private NotificationService notificationService;
/**
* dependency
*/
private EventTrackingService eventTrackingService;
/**
* dependency
*/
private UserDirectoryService userDirectoryService;
/**
* dependency
*/
private SessionManager sessionManager;
private static final String DIGEST_STORE_FOLDER = "/searchdigest/";
/**
* Optional dependencies
*/
private List<String> triggerFunctions;
/**
* the notification object
*/
private NotificationEdit notification = null;
protected IndexStorage indexStorage;
/**
* init completed
*/
protected boolean initComplete = false;
private SearchItemFilter filter;
private Map luceneFilters = new HashMap();
private Map luceneSorters = new HashMap();
private String defaultFilter = null;
private String defaultSorter = null;
private String sharedKey = null;
private String searchServerUrl = null;
private boolean searchServer = false;
private ThreadLocal<String> localSearch = new ThreadLocal<String>();
private HttpClient httpClient;
private HttpConnectionManagerParams httpParams = new HttpConnectionManagerParams();
private HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
/** Configuration: to run the ddl on init or not. */
protected boolean autoDdl = false;
private boolean diagnostics;
private boolean enabled;
private JournalSettings journalSettings;
public void setJournalSettings(JournalSettings journalSettings) {
this.journalSettings = journalSettings;
}
public abstract String getStatus();
public abstract SearchStatus getSearchStatus();
public abstract boolean removeWorkerLock();
/**
* Configuration: to run the ddl on init or not.
*
* @param value
* the auto ddl value.
*/
public void setAutoDdl(String value)
{
autoDdl = Boolean.valueOf(value).booleanValue();
}
/**
*/
public String getAutoDdl()
{
return String.valueOf(autoDdl);
}
/**
* Register a notification action to listen to events and modify the search
* index
*/
public void init()
{
try
{
// register a transient notification for resources
notification = notificationService.addTransientNotification();
// add all the functions that are registered to trigger search index
// modification
notification.setFunction(SearchService.EVENT_TRIGGER_SEARCH);
if (triggerFunctions != null)
{
for (Iterator<String> ifn = triggerFunctions.iterator(); ifn.hasNext();)
{
String function = (String) ifn.next();
notification.addFunction(function);
if (log.isDebugEnabled())
{
log.debug("Adding Search Register " + function); //$NON-NLS-1$
}
}
}
// set the filter to any site related resource
notification.setResourceFilter("/"); //$NON-NLS-1$
// set the action
notification.setAction(new SearchNotificationAction(searchIndexBuilder));
// Configure params for the Connection Manager
httpParams.setDefaultMaxConnectionsPerHost(20);
httpParams.setMaxTotalConnections(30);
// This next line may not be necessary since we specified default 2
// lines ago, but here it is anyway
httpParams.setMaxConnectionsPerHost(HostConfiguration.ANY_HOST_CONFIGURATION,
20);
// Set up the connection manager
httpConnectionManager.setParams(httpParams);
// Finally set up the static multithreaded HttpClient
httpClient = new HttpClient(httpConnectionManager);
if (diagnostics)
{
indexStorage.enableDiagnostics();
}
else
{
indexStorage.disableDiagnostics();
}
indexStorage.addReloadListener(new IndexReloadListener() {
public void reloaded(long reloadStart, long reloadEnd)
{
if (diagnostics)
{
log.info("Index Reloaded containing " + getNDocs()
+ " active documents and " + getPendingDocs()
+ " pending documents in " + (reloadEnd - reloadStart)
+ "ms");
}
}
});
}
catch (Throwable t)
{
log.error("Failed to start ", t); //$NON-NLS-1$
}
}
/**
* @return Returns the triggerFunctions.
*/
public List<String> getTriggerFunctions()
{
return triggerFunctions;
}
/**
* @param triggerFunctions
* The triggerFunctions to set.
*/
public void setTriggerFunctions(List<String> triggerFunctions)
{
if (initComplete)
throw new RuntimeException(
" use register function at runtime, setTriggerFucntions is for Spring IoC only"); //$NON-NLS-1$
this.triggerFunctions = triggerFunctions;
}
/**
* {@inheritDoc}
*/
public void registerFunction(String function)
{
notification.addFunction(function);
if (log.isDebugEnabled())
{
log.debug("Adding Function " + function); //$NON-NLS-1$
}
}
/**
* {@inheritDoc}
*
* @param indexFilter
*/
public SearchList search(String searchTerms, List<String> contexts, int start, int end) throws InvalidSearchQueryException
{
return search(searchTerms, contexts, start, end, defaultFilter, defaultSorter);
}
public SearchList search(String searchTerms, List<String> contexts, int start, int end,
String filterName, String sorterName) throws InvalidSearchQueryException
{
try
{
BooleanQuery query = new BooleanQuery();
QueryParser qp = new QueryParser(Version.LUCENE_29,SearchService.FIELD_CONTENTS, getAnalyzer());
Query textQuery = qp.parse(searchTerms);
// Support cross context searches
if (contexts != null && contexts.size() > 0)
{
BooleanQuery contextQuery = new BooleanQuery();
for (Iterator<String> i = contexts.iterator(); i.hasNext();)
{
// Setup query so that it will allow results from any
// included site, not all included sites.
contextQuery.add(new TermQuery(new Term(SearchService.FIELD_SITEID,
(String) i.next())), BooleanClause.Occur.SHOULD);
// This would require term to be in all sites :-(
// contextQuery.add(new TermQuery(new Term(
// SearchService.FIELD_SITEID, (String) i.next())),
// BooleanClause.Occur.MUST);
}
query.add(contextQuery, BooleanClause.Occur.MUST);
}
query.add(textQuery, BooleanClause.Occur.MUST);
log.debug("Compiled Query is " + query.toString()); //$NON-NLS-1$
if (localSearch.get() == null && searchServerUrl != null
&& searchServerUrl.length() > 0)
{
try
{
PostMethod post = new PostMethod(searchServerUrl);
String userId = sessionManager.getCurrentSessionUserId();
StringBuilder sb = new StringBuilder();
for (Iterator<String> ci = contexts.iterator(); ci.hasNext();)
{
sb.append(ci.next()).append(";"); //$NON-NLS-1$
}
String contextParam = sb.toString();
post.setParameter(REST_CHECKSUM, digestCheck(userId, searchTerms));
post.setParameter(REST_CONTEXTS, contextParam);
post.setParameter(REST_END, String.valueOf(end));
post.setParameter(REST_START, String.valueOf(start));
post.setParameter(REST_TERMS, searchTerms);
post.setParameter(REST_USERID, userId);
int status = httpClient.executeMethod(post);
if (status != 200)
{
throw new RuntimeException(
"Failed to perform remote search, http status was " + status); //$NON-NLS-1$
}
String response = post.getResponseBodyAsString();
return new SearchListResponseImpl(response, textQuery, start, end,
getAnalyzer(), filter, searchIndexBuilder, this);
}
catch (Exception ex)
{
log.error("Remote Search Failed ", ex); //$NON-NLS-1$
throw new IOException(ex.getMessage());
}
}
else
{
IndexSearcher indexSearcher = getIndexSearcher(false);
int MAX_RESULTS = 1000000;
if (indexSearcher != null)
{
TopDocs topDocs = null;
Filter indexFilter = (Filter) luceneFilters.get(filterName);
Sort indexSorter = (Sort) luceneSorters.get(sorterName);
if (log.isDebugEnabled())
{
log.debug("Using Filter " + filterName + ":" //$NON-NLS-1$ //$NON-NLS-2$
+ indexFilter + " and " + sorterName + ":" //$NON-NLS-1$ //$NON-NLS-2$
+ indexSorter);
}
if (indexFilter != null && indexSorter != null)
{
topDocs = indexSearcher.search(query, indexFilter, MAX_RESULTS, indexSorter);
}
else if (indexFilter != null)
{
topDocs = indexSearcher.search(query, indexFilter, MAX_RESULTS);
}
else if (indexSorter != null)
{
topDocs = indexSearcher.search(query, null, MAX_RESULTS, indexSorter);
}
else
{
topDocs = indexSearcher.search(query, MAX_RESULTS);
}
if (log.isDebugEnabled())
{
log.debug("Got " + topDocs.totalHits + " hits"); //$NON-NLS-1$ //$NON-NLS-2$
}
String context = null;
if (contexts != null && contexts.size() > 0)
{
//seeing events doesn't support multi context use the first
context = contexts.get(0);
}
eventTrackingService.post(eventTrackingService.newEvent(EVENT_SEARCH,
EVENT_SEARCH_REF + textQuery.toString(), context, true,
NotificationService.PREF_IMMEDIATE));
return new SearchListImpl(topDocs, indexSearcher, textQuery, start, end,
getAnalyzer(), filter, searchIndexBuilder, this);
}
else
{
throw new RuntimeException(
"Failed to start the Lucene Searche Engine"); //$NON-NLS-1$
}
}
}
catch (ParseException e)
{
throw new InvalidSearchQueryException("Failed to parse Query ", e); //$NON-NLS-1$
}
catch (IOException e)
{
throw new RuntimeException("Failed to run Search ", e); //$NON-NLS-1$
}
}
public void refreshInstance()
{
searchIndexBuilder.refreshIndex();
}
public void rebuildInstance()
{
searchIndexBuilder.rebuildIndex();
}
public void refreshSite(String currentSiteId)
{
searchIndexBuilder.refreshIndex(currentSiteId);
}
public void rebuildSite(String currentSiteId)
{
searchIndexBuilder.rebuildIndex(currentSiteId);
}
/**
* {@inheritDoc}
*/
public void reload()
{
getIndexSearcher(true);
}
public void forceReload()
{
indexStorage.forceNextReload();
}
/**
* The sequence is, peform reload,
*
* @param reload
* @return
*/
public IndexSearcher getIndexSearcher(boolean reload)
{
try
{
return indexStorage.getIndexSearcher(reload);
}
catch (Exception ex)
{
log.error("Failed to get an index searcher ", ex);
throw new RuntimeException("Failed to get an index searcher ", ex);
}
}
public int getNDocs()
{
try
{
return getIndexSearcher(false).getIndexReader().numDocs();
}
catch (Exception e)
{
return -1;
}
}
public int getPendingDocs()
{
return searchIndexBuilder.getPendingDocuments();
}
public List<SearchBuilderItem> getAllSearchItems()
{
return searchIndexBuilder.getAllSearchItems();
}
public List<SearchBuilderItem> getSiteMasterSearchItems()
{
return searchIndexBuilder.getSiteMasterSearchItems();
}
public List<SearchBuilderItem> getGlobalMasterSearchItems()
{
return searchIndexBuilder.getGlobalMasterSearchItems();
}
/**
* @return Returns the filter.
*/
public SearchItemFilter getFilter()
{
return filter;
}
/**
* @param filter
* The filter to set.
*/
public void setFilter(SearchItemFilter filter)
{
this.filter = filter;
}
/**
* @return Returns the defaultFilter.
*/
public String getDefaultFilter()
{
return defaultFilter;
}
/**
* @param defaultFilter
* The defaultFilter to set.
*/
public void setDefaultFilter(String defaultFilter)
{
this.defaultFilter = defaultFilter;
}
/**
* @return Returns the defaultSorter.
*/
public String getDefaultSorter()
{
return defaultSorter;
}
/**
* @param defaultSorter
* The defaultSorter to set.
*/
public void setDefaultSorter(String defaultSorter)
{
this.defaultSorter = defaultSorter;
}
/**
* @return Returns the luceneFilters.
*/
public Map getLuceneFilters()
{
return luceneFilters;
}
/**
* @param luceneFilters
* The luceneFilters to set.
*/
public void setLuceneFilters(Map luceneFilters)
{
this.luceneFilters = luceneFilters;
}
/**
* @return Returns the luceneSorters.
*/
public Map getLuceneSorters()
{
return luceneSorters;
}
/**
* @param luceneSorters
* The luceneSorters to set.
*/
public void setLuceneSorters(Map luceneSorters)
{
this.luceneSorters = luceneSorters;
}
public TermFrequency getTerms(int documentId) throws IOException
{
final TermFreqVector tf = getIndexSearcher(false).getIndexReader()
.getTermFreqVector(documentId, FIELD_CONTENTS);
return new TermFrequency()
{
public String[] getTerms()
{
if (tf != null)
{
return tf.getTerms();
}
return new String[0];
}
public int[] getFrequencies()
{
if (tf != null)
{
return tf.getTermFrequencies();
}
return new int[0];
}
};
}
public String searchXML(Map parameterMap)
{
String userid = null;
String searchTerms = null;
String checksum = null;
String contexts = null;
String ss = null;
String se = null;
try
{
if (!searchServer)
{
throw new Exception(Messages.getString("SearchServiceImpl.49")); //$NON-NLS-1$
}
String[] useridA = (String[]) parameterMap.get(REST_USERID);
String[] searchTermsA = (String[]) parameterMap.get(REST_TERMS);
String[] checksumA = (String[]) parameterMap.get(REST_CHECKSUM);
String[] contextsA = (String[]) parameterMap.get(REST_CONTEXTS);
String[] ssA = (String[]) parameterMap.get(REST_START);
String[] seA = (String[]) parameterMap.get(REST_END);
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\"?>"); //$NON-NLS-1$
boolean requestError = false;
if (useridA == null || useridA.length != 1)
{
requestError = true;
}
else
{
userid = useridA[0];
}
if (searchTermsA == null || searchTermsA.length != 1)
{
requestError = true;
}
else
{
searchTerms = searchTermsA[0];
}
if (checksumA == null || checksumA.length != 1)
{
requestError = true;
}
else
{
checksum = checksumA[0];
}
if (contextsA == null || contextsA.length != 1)
{
requestError = true;
}
else
{
contexts = contextsA[0];
}
if (ssA == null || ssA.length != 1)
{
requestError = true;
}
else
{
ss = ssA[0];
}
if (seA == null || seA.length != 1)
{
requestError = true;
}
else
{
se = seA[0];
}
if (requestError)
{
throw new Exception(Messages.getString("SearchServiceImpl.34")); //$NON-NLS-1$
}
int searchStart = Integer.parseInt(ss);
int searchEnd = Integer.parseInt(se);
String[] ctxa = contexts.split(";"); //$NON-NLS-1$
List<String> ctx = new ArrayList<String>(ctxa.length);
for (int i = 0; i < ctxa.length; i++)
{
ctx.add(ctxa[i]);
}
if (sharedKey != null && sharedKey.length() > 0)
{
String check = digestCheck(userid, searchTerms);
if (!check.equals(checksum))
{
throw new Exception(Messages.getString("SearchServiceImpl.53")); //$NON-NLS-1$
}
}
org.sakaiproject.tool.api.Session s = sessionManager.startSession();
User u = userDirectoryService.getUser("admin"); //$NON-NLS-1$
s.setUserId(u.getId());
sessionManager.setCurrentSession(s);
localSearch.set("localsearch"); //$NON-NLS-1$
try
{
SearchList sl = search(searchTerms, ctx, searchStart, searchEnd);
sb.append("<results "); //$NON-NLS-1$
sb.append(" fullsize=\"").append(sl.getFullSize()) //$NON-NLS-1$
.append("\" "); //$NON-NLS-1$
sb.append(" start=\"").append(sl.getStart()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
sb.append(" size=\"").append(sl.size()).append("\" "); //$NON-NLS-1$ //$NON-NLS-2$
sb.append(" >"); //$NON-NLS-1$
for (Iterator<SearchResult> si = sl.iterator(); si.hasNext();)
{
SearchResult sr = (SearchResult) si.next();
sr.toXMLString(sb);
}
sb.append("</results>"); //$NON-NLS-1$
return sb.toString();
}
finally
{
sessionManager.setCurrentSession(null);
localSearch.set(null);
}
}
catch (Exception ex)
{
log.error("Search Service XML response failed ",ex);
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\"?>"); //$NON-NLS-1$
sb.append("<fault>"); //$NON-NLS-1$
sb.append("<request>"); //$NON-NLS-1$
sb.append("<![CDATA["); //$NON-NLS-1$
sb.append(" userid = ").append(StringEscapeUtils.escapeXml(userid)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb
.append(" searchTerms = ").append(StringEscapeUtils.escapeXml(searchTerms)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb
.append(" checksum = ").append(StringEscapeUtils.escapeXml(checksum)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb
.append(" contexts = ").append(StringEscapeUtils.escapeXml(contexts)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append(" ss = ").append(StringEscapeUtils.escapeXml(ss)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append(" se = ").append(StringEscapeUtils.escapeXml(se)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
sb.append("]]>"); //$NON-NLS-1$
sb.append("</request>"); //$NON-NLS-1$
sb.append("<error>"); //$NON-NLS-1$
sb.append("<![CDATA["); //$NON-NLS-1$
try
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
sb.append(sw.toString());
pw.close();
sw.close();
}
catch (Exception ex2)
{
sb.append("Failed to serialize exception " + ex.getMessage()) //$NON-NLS-1$
.append("\n"); //$NON-NLS-1$
sb.append("Case: " + ex2.getMessage()); //$NON-NLS-1$
}
sb.append("]]>"); //$NON-NLS-1$
sb.append("</error>"); //$NON-NLS-1$
sb.append("</fault>"); //$NON-NLS-1$
return sb.toString();
}
}
private String digestCheck(String userid, String searchTerms)
throws GeneralSecurityException, IOException
{
MessageDigest sha1 = MessageDigest.getInstance("SHA1"); //$NON-NLS-1$
String chstring = sharedKey + userid + searchTerms;
return byteArrayToHexStr(sha1.digest(chstring.getBytes("UTF-8"))); //$NON-NLS-1$
}
private static String byteArrayToHexStr(byte[] data)
{
char[] chars = new char[data.length * 2];
for (int i = 0; i < data.length; i++)
{
byte current = data[i];
int hi = (current & 0xF0) >> 4;
int lo = current & 0x0F;
chars[2 * i] = (char) (hi < 10 ? ('0' + hi) : ('A' + hi - 10));
chars[2 * i + 1] = (char) (lo < 10 ? ('0' + lo) : ('A' + lo - 10));
}
return new String(chars);
}
/**
* @return the sharedKey
*/
public String getSharedKey()
{
return sharedKey;
}
/**
* @param sharedKey
* the sharedKey to set
*/
public void setSharedKey(String sharedKey)
{
this.sharedKey = sharedKey;
}
/**
* @return the searchServerUrl
*/
public String getSearchServerUrl()
{
return searchServerUrl;
}
/**
* @param searchServerUrl
* the searchServerUrl to set
*/
public void setSearchServerUrl(String searchServerUrl)
{
this.searchServerUrl = searchServerUrl;
}
/**
* @return the searchServer
*/
public boolean isSearchServer()
{
return searchServer;
}
/**
* @param searchServer
* the searchServer to set
*/
public void setSearchServer(boolean searchServer)
{
this.searchServer = searchServer;
}
public boolean getDiagnostics()
{
return hasDiagnostics();
}
public void setDiagnostics(boolean diagnostics)
{
if (diagnostics)
{
enableDiagnostics();
}
else
{
disableDiagnostics();
}
}
/**
* @return the eventTrackingService
*/
public EventTrackingService getEventTrackingService()
{
return eventTrackingService;
}
/**
* @param eventTrackingService the eventTrackingService to set
*/
public void setEventTrackingService(EventTrackingService eventTrackingService)
{
this.eventTrackingService = eventTrackingService;
}
/**
* @return the notificationService
*/
public NotificationService getNotificationService()
{
return notificationService;
}
/**
* @param notificationService the notificationService to set
*/
public void setNotificationService(NotificationService notificationService)
{
this.notificationService = notificationService;
}
/**
* @return the searchIndexBuilder
*/
public SearchIndexBuilder getSearchIndexBuilder()
{
return searchIndexBuilder;
}
/**
* @param searchIndexBuilder the searchIndexBuilder to set
*/
public void setSearchIndexBuilder(SearchIndexBuilder searchIndexBuilder)
{
this.searchIndexBuilder = searchIndexBuilder;
}
/**
* @return the sessionManager
*/
public SessionManager getSessionManager()
{
return sessionManager;
}
/**
* @param sessionManager the sessionManager to set
*/
public void setSessionManager(SessionManager sessionManager)
{
this.sessionManager = sessionManager;
}
/**
* @return the userDirectoryService
*/
public UserDirectoryService getUserDirectoryService()
{
return userDirectoryService;
}
/**
* @param userDirectoryService the userDirectoryService to set
*/
public void setUserDirectoryService(UserDirectoryService userDirectoryService)
{
this.userDirectoryService = userDirectoryService;
}
/**
* @return Returns the indexStorage.
*/
public IndexStorage getIndexStorage()
{
return indexStorage;
}
/**
* @param indexStorage
* The indexStorage to set.
*/
public void setIndexStorage(IndexStorage indexStorage)
{
this.indexStorage = indexStorage;
}
protected Analyzer getAnalyzer()
{
return indexStorage.getAnalyzer();
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.Diagnosable#disableDiagnostics()
*/
public void disableDiagnostics()
{
diagnostics = false;
if (indexStorage != null)
{
indexStorage.disableDiagnostics();
}
}
/*
* (non-Javadoc)
*
* @see org.sakaiproject.search.api.Diagnosable#enableDiagnostics()
*/
public void enableDiagnostics()
{
diagnostics = true;
if (indexStorage != null)
{
indexStorage.enableDiagnostics();
}
}
/**
* @see org.sakaiproject.search.api.Diagnosable#hasDiagnostics()
*/
public boolean hasDiagnostics()
{
return diagnostics;
}
public List getSegmentInfo()
{
return indexStorage.getSegmentInfoList();
}
/* (non-Javadoc)
* @see org.sakaiproject.search.api.SearchService#isEnabled()
*/
public boolean isEnabled()
{
enabled = ServerConfigurationService.getBoolean("search.enable",false);
log.info("Enable = "
+ ServerConfigurationService.getString("search.enable", "false"));
enabled = enabled && ServerConfigurationService.getBoolean("search.indexbuild",true);
return enabled;
}
public String getDigestStoragePath() {
String customPath = ServerConfigurationService.getString("search.digestPath");
String storePath = null;
if (customPath == null || "".equals(customPath)) {
storePath = ServerConfigurationService.getString("bodyPath@org.sakaiproject.content.api.ContentHostingService");
if (storePath == null || "".equals(storePath)) {
return null;
}
} else {
storePath = customPath;
}
return storePath + "/" + DIGEST_STORE_FOLDER;
}
Directory spellIndexDirectory = null;
public String[] getSearchSuggestions(String searchString, String currentSiteId, boolean allMySites) {
String suggestion = getSearchSuggestion(searchString);
if (suggestion != null && suggestion.length() > 0) {
return new String[]{searchString};
}
return new String[]{};
}
public String getSearchSuggestion(String queryString) {
log.info("getSearchSuggestion( " + queryString + ")");
if (!ServerConfigurationService.getBoolean("search.experimental.didyoumean", false)) {
log.info("did you mean feature is not enabled");
return null;
}
if (spellIndexDirectory == null) {
spellIndexDirectory = indexStorage.getSpellDirectory();
}
//if its still null we we'rent able to create a spellindex
if (spellIndexDirectory == null) {
log.info("Spell index is not available");
return null;
}
//the reader to the original index:
IndexReader indexReaderOrigional = null;
try {
indexReaderOrigional = indexStorage.getIndexReader();
} catch (CorruptIndexException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
DidYouMeanParser parser = new DidYouMeanParser(SearchService.FIELD_CONTENTS, spellIndexDirectory, indexReaderOrigional);
try {
Query query = parser.suggest(queryString);
//the service may have no suggestions
if (query != null) {
log.debug("got suggestion: " + query.toString(SearchService.FIELD_CONTENTS));
return query.toString(SearchService.FIELD_CONTENTS);
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}