/*
* Copyright (C) 2004 Paul Browne, http://www.firstpartners.net,
* built with the help of Fast-Soft (fastsoftdev@yahoo.com)
*
* released under terms of the GPL license
* http://www.opensource.org/licenses/gpl-license.php
*
* This product includes software developed by the
* Apache Software Foundation (http://www.apache.org)."
*
* This product includes software developed by the
* Spring Framework Project (http://www.springframework.org)."
*
*/
package net.fp.rp.search.mid.global;
import net.fp.rp.common.exception.RpException;
import net.fp.rp.search.back.extractor.util.UtilExtract;
import net.fp.rp.search.back.search.SearchQuery;
import net.fp.rp.search.back.struct.DocumStruct;
import net.fp.rp.search.common.AddInfo;
import net.fp.rp.search.common.util.MessageUtil;
import net.fp.rp.search.common.util.Util;
import net.fp.rp.search.mid.feedback.BaseFeedback;
import net.fp.rp.search.mid.feedback.SearchFeedback;
import net.fp.rp.search.plugins.IFeedbackDataStore;
import net.fp.rp.search.plugins.ISearchResult;
import net.fp.rp.search.plugins.events.IInterestedInAdd;
import net.fp.rp.search.plugins.events.IInterestedInFeedback;
import net.fp.rp.search.plugins.events.IInterestedInSearch;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The UI (Web / Command Line / Other) pass commands to here for them to be
* carried out
*
* @author brownpa
* Copyright @link www.firstpartners.net/red
*/
public class KnowledgeSphereManager {
/** log for this class and subclasses */
protected final Logger log = Logger.getLogger(getClass());
/** Plugin manager */
private PluginManager pluginManager;
/** Maximum wait time for search operation */
private int maxWaitSearchTime;
/** The count of documents that the searcher may be interested in*/
private int searchCount;
/** Feedback controller */
private boolean feedbackAllow;
/**
* Allows us to set (via Spring) the information that will get added at startup
*/
private static String addOnStartup=null;
/**
* Whether we use threading or not
*/
private boolean useThreading =true;
/**
* Initialization of the manager ( initialization of the log4j)
*/
public KnowledgeSphereManager() {
init();
}
/**
* An init method , available to spring as well, that checks to see
* if there is any information that needs to be added on startup
*/
public void init(){
if(addOnStartup==null){
log.info("No Information set to be added on Startup");
} else {
log.info("Information to be added on startup:"+addOnStartup);
String info = add(addOnStartup);
log.info("Results of Adding information at startup:"+info);
}
}
/**
* Add a piece of information to the system
*
* @param somethingToAdd
*
* @return Result message of adding the information to the system
*/
public String add(final String somethingToAdd) {
//get the list of plugins which implement the IInteresetedInAdd interface
log.info("KnowledgeManager - adding the information to the system");
String uri = UtilExtract.getUri(somethingToAdd);
log.debug("Validate if the information " + uri + " is a valid uri");
if (UtilExtract.isValidUriLocation(uri)) {
try {
IInterestedInAdd[] addPlugins = PluginManager.getInterestedInAdd();
log.debug("Number of plugins to carry out add of information:"+addPlugins.length);
//define the information object
AddInfo info = new AddInfo(somethingToAdd, uri);
log.debug("Piece of information that we are adding:"+info);
for (int i = 0; i < addPlugins.length; i++) {
log.debug("Iterate on plugins and call the add function:"+i);
//in orde to have the control in the manager over the priority
//add the thread to the list to be controlled
PluginManager.addPluginThread(addPlugins[i], info,useThreading);
}
//get the message from resource message
String message = MessageUtil.getMessage("app.add.status.ok",
new Object[] { uri });
return message;
} catch (RpException e) {
//RpException in getting the plugins InAdd
log.warn("Exception in add " , e);
String message = e.getMessage();
return message;
}
} else {
String message = MessageUtil.getMessage("app.location.notvalid",
new Object[] { uri });
return message;
}
}
/**
* Search for information
*
* @param somethingToSearch Information to search
* @param score DOCUMENT ME!
*
* @return Map containing all the information about the search :
* 1.startno,endno,list of documents found it, search query)
* 2.error in case that no information is available
*/
public Map search(String somethingToSearch, final int score) {
//increase the performance (set low priority for active plugins)
Map myModel = new HashMap();
//add the search query to the model
myModel.put(ModelView.SEARCHQUERY, somethingToSearch);
//add the search term to the model
myModel.put(ModelView.SEARCHTERM, Util.getSearchTerm(somethingToSearch));
long start = System.currentTimeMillis();
log.debug("Mark all the running plugin-threads in LOW priority mode");
pluginManager.startSearchOp();
try {
//store the query as feedback information only if the feedback is allow
if (feedbackAllow) {
try {
//store the feedback data
final SearchFeedback advice = new SearchFeedback(score,
somethingToSearch);
if(PluginManager.getFeedbackDataStores()!=null){
PluginManager.getFeedbackDataStores().save(advice);
}
//start a new process in background to recalculate the scores
IInterestedInFeedback[] feedbackPlugins = PluginManager.getInterestedInFeedback();
for (int i = 0; i < feedbackPlugins.length; i++) {
final IInterestedInFeedback feedbackPlugin = feedbackPlugins[i];
Thread t = new Thread(new Runnable() {
public void run() {
try {
feedbackPlugin.acceptFeedback(advice);
} catch (RpException e) {
log.warn("Exception in feedback from search",e);
}
}
});
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
} catch (RpException e) {
//Exception in getting the FeedbackDataStore
log.warn("Exception in getting the feedbackdatastore " +
e.getMessage(), e);
}
}
IInterestedInSearch[] plugins = PluginManager.getInterestedInSearch();
log.debug("Number of plugins able to carry out search:"+plugins.length);
SearchQuery query = new SearchQuery(somethingToSearch);
//do the search
for (int i = 0; i < plugins.length; i++) {
plugins[i].doSearch(query, DocumStruct.FIELD_SORT_SCORE, true,
searchCount,useThreading);
}
//wait till all the search plugins are done or time out was reached
if(useThreading){
boolean wait = true;
log.debug(
"Wait for plugin to finish the search operation (plugins are ready or time expired)");
while (wait && !Util.isTimeExpired(start, maxWaitSearchTime)) {
wait = false;
for (int i = 0; i < plugins.length; i++) {
if (!plugins[i].isReady()) {
wait = true;
}
}
}
}
//iterate on the plugins and gather the result:startno,endno,list of documents found it, search query)
int countErrors = 0;
int countHits = 0;
List allDocs = new ArrayList();
for (int i = 0; i < plugins.length; i++) {
ISearchResult result = plugins[i].getResults();
countHits = countHits + result.getCountFound();
countErrors = countErrors + result.getCountErrors();
allDocs.addAll(result.getDocuments());
}
if (allDocs.size() > 0) {
//we found documents (maybe with errors
myModel.put(ModelView.STARTNO, "1");
myModel.put(ModelView.ENDNO, String.valueOf(allDocs.size()));
myModel.put(ModelView.DOCUMENTSNO,
String.valueOf(allDocs.size()));
myModel.put(ModelView.DOCUMENTS, allDocs);
myModel.put(ModelView.ERROR, "false");
float elapsedTimeMillis = (System.currentTimeMillis() - start) / 1000F;
myModel.put(ModelView.SEARCHTIME,
String.valueOf(elapsedTimeMillis));
if (countErrors == 0) {
myModel.put(ModelView.STATUS,
MessageUtil.getMessage("app.search.status.noerror"));
} else {
myModel.put(ModelView.STATUS,
MessageUtil.getMessage("app.search.status.errors",
new Object[] { String.valueOf(countErrors) }));
}
} else {
//no document was found it
log.debug("No pages were found containing " +
query.getQuery());
myModel.put(ModelView.ERROR, "true");
myModel.put(ModelView.STATUS,
MessageUtil.getMessage("app.search.status.nopage",
new Object[] { query.getQuery() }));
}
} catch (RpException e) {
log.warn("Exception in search " + e.getMessage(), e);
myModel.put(ModelView.ERROR, "true");
myModel.put(ModelView.STATUS, e.getMessage());
} finally {
log.debug(
"Mark all the running plugin-threads in HIGH priority mode");
pluginManager.endSearchOp();
}
return myModel;
}
/**
* Give feedback on a piece of information
*
* @param advice Feedback object (search, document or category feedback)
* @param searchterm Default score of the feedback
*
* @return resultCode
*/
public Map feedback(final BaseFeedback advice, final String searchterm) {
log.info("KnowledgeManager - feedback process");
//if feedback is allow then store it and update the links
if (feedbackAllow) {
try {
//store the feedback
IFeedbackDataStore store = PluginManager.getFeedbackDataStores();
store.save(advice);
//notify the feedback plugins to recalculate the score
IInterestedInFeedback[] feedbackPlugins = PluginManager.getInterestedInFeedback();
for (int i = 0; i < feedbackPlugins.length; i++) {
feedbackPlugins[i].acceptFeedback(advice);
}
//make a search for the specified type
return search(searchterm, advice.getScore());
} catch (RpException e) {
//Exception in getting the FeedbackDataStore or pluginsFeedback
log.warn("Exception in feedback " + e.getMessage(), e);
//define a model and specify the error
Map myModel = new HashMap();
myModel.put(ModelView.ERROR, "true");
myModel.put(ModelView.STATUS, e.getMessage());
return myModel;
}
} else {
//feedback process is not allow in the system
//define a model and specify the error
Map myModel = new HashMap();
myModel.put(ModelView.ERROR, "true");
myModel.put(ModelView.STATUS,
MessageUtil.getMessage("app.feedback.notallow"));
return myModel;
}
}
/**
* @return Returns the pluginManager.
*/
public PluginManager getPluginManager() {
return pluginManager;
}
/**
* @param pluginManager The pluginManager to set.
*/
public void setPluginManager(PluginManager pluginManager) {
this.pluginManager = pluginManager;
}
/**
* @return Returns the maxWaitSearchTime.
*/
public int getMaxWaitSearchTime() {
return maxWaitSearchTime;
}
/**
* @param maxWaitSearchTime The maxWaitSearchTime to set.
*/
public void setMaxWaitSearchTime(int maxWaitSearchTime) {
this.maxWaitSearchTime = maxWaitSearchTime;
}
/**
* @return Returns the feedbackAllow.
*/
public boolean getFeedbackAllow() {
return feedbackAllow;
}
/**
* @param feedbackAllow The feedbackAllow to set.
*/
public void setFeedbackAllow(boolean feedbackAllow) {
this.feedbackAllow = feedbackAllow;
}
/**
* @return Returns the searchCount.
*/
public int getSearchCount() {
return searchCount;
}
/**
* @param searchCount The searchCount to set.
*/
public void setSearchCount(int searchCount) {
this.searchCount = searchCount;
}
/**
* @param useThreading The useThreading to set.
*/
public void setUseThreading(boolean useThreading) {
this.useThreading = useThreading;
}
/**
* @return Returns the useThreading.
*/
public boolean getUseThreading() {
return useThreading;
}
/**
* @param addOnStartup The addOnStartup to set.
*/
public void setAddOnStartup(String addOnStartup) {
this.addOnStartup = addOnStartup;
}
/**
* @return Returns the addOnStartup.
*/
public static String getAddOnStartup() {
return addOnStartup;
}
}