Java tutorial
/* * SearchEnginePlugIn.java * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Author: Winter Lau (javayou@gmail.com) * http://dlog4j.sourceforge.net */ package com.liusoft.dlog4j.plugin; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Properties; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.action.ActionServlet; import org.apache.struts.config.ModuleConfig; import com.liusoft.dlog4j.Globals; import com.liusoft.dlog4j.db.HibernateUtils; import com.liusoft.dlog4j.search.SearchDataProvider; import com.liusoft.dlog4j.search.SearchEnabled; import com.liusoft.dlog4j.search.SearchProxy; import com.liusoft.dlog4j.util.StringUtils; /** * <p>A search engine daemon using lucene implements struts's plugin</p> * <p>This plugin require a property named "basePath" * to indicate where the lucene files stored.</p> * <p> * In UNIX or Linux OS, you must use "file://" to a no-webapp-context path<br/> * Example: "file:///data/lucene" refer to /data/lucene but {webapp}/data/lucene * </p> * @author Winter Lau */ public class SearchEnginePlugIn extends DaemonPlugin { private String basePath; private String dataProvider0; private String dataProvider1; private String dataProvider2; private String dataProvider3; private String dataProvider4; private String dataProvider5; private String dataProvider6; private String dataProvider7; private String dataProvider8; private String dataProvider9; private ThreadGroup tGroup = new ThreadGroup("build_idx_thread"); private boolean stop = false; /** * ?? */ public void init(ActionServlet servlet, ModuleConfig config) throws ServletException { if (basePath.startsWith(Globals.LOCAL_PATH_PREFIX)) { basePath = basePath.substring(Globals.LOCAL_PATH_PREFIX.length()); } else if (basePath.startsWith("/")) { basePath = servlet.getServletContext().getRealPath(basePath); } //??? SearchProxy.init(basePath); super.init(servlet, config); } public void destroy() { stop = true; int tCount = tGroup.activeCount(); if (tCount > 0) { Thread[] threads = new Thread[tCount]; int tc = tGroup.enumerate(threads); for (int i = 0; i < tc; i++) { if (threads[i] instanceof BuildIndexThread) try { threads[i].join(10000, 200); } catch (InterruptedException e) { log.error("Exception occurred when waiting for thread " + threads[i].getClass().getName(), e); } } } super.destroy(); } /** * build */ protected void service() throws Exception { if (StringUtils.isNotEmpty(dataProvider0)) buildIndexes(dataProvider0); if (StringUtils.isNotEmpty(dataProvider1)) buildIndexes(dataProvider1); if (StringUtils.isNotEmpty(dataProvider2)) buildIndexes(dataProvider2); if (StringUtils.isNotEmpty(dataProvider3)) buildIndexes(dataProvider3); if (StringUtils.isNotEmpty(dataProvider4)) buildIndexes(dataProvider4); if (StringUtils.isNotEmpty(dataProvider5)) buildIndexes(dataProvider5); if (StringUtils.isNotEmpty(dataProvider6)) buildIndexes(dataProvider6); if (StringUtils.isNotEmpty(dataProvider7)) buildIndexes(dataProvider7); if (StringUtils.isNotEmpty(dataProvider8)) buildIndexes(dataProvider8); if (StringUtils.isNotEmpty(dataProvider9)) buildIndexes(dataProvider9); } /** * * TODO: ??? * @param providerClass * @param lastTime */ private int buildIndexes(final String providerClass) { if (stop) return -1; new BuildIndexThread(context(), tGroup, providerClass).start(); return 0; } protected String name() { return "search_engine"; } public void setBasePath(String basePath) { this.basePath = basePath; } public void setDataProvider0(String dataProvider0) { this.dataProvider0 = dataProvider0; } public void setDataProvider1(String dataProvider1) { this.dataProvider1 = dataProvider1; } public void setDataProvider2(String dataProvider2) { this.dataProvider2 = dataProvider2; } public void setDataProvider3(String dataProvider3) { this.dataProvider3 = dataProvider3; } public void setDataProvider4(String dataProvider4) { this.dataProvider4 = dataProvider4; } public void setDataProvider5(String dataProvider5) { this.dataProvider5 = dataProvider5; } public void setDataProvider6(String dataProvider6) { this.dataProvider6 = dataProvider6; } public void setDataProvider7(String dataProvider7) { this.dataProvider7 = dataProvider7; } public void setDataProvider8(String dataProvider8) { this.dataProvider8 = dataProvider8; } public void setDataProvider9(String dataProvider9) { this.dataProvider9 = dataProvider9; } } /** * * @author liudong */ class BuildIndexThread extends Thread { protected final static Log log = LogFactory.getLog(BuildIndexThread.class); private ServletContext context; private String providerClass; public BuildIndexThread(ServletContext context, ThreadGroup group, String providerClass) { super(group, providerClass); this.context = context; this.providerClass = providerClass; } public void run() { List objs = null; try { Date lastTime = getLastActiveTime(providerClass); SearchDataProvider sdp = (SearchDataProvider) Class.forName(providerClass).newInstance(); if (lastTime == null) lastTime = new Date(0); objs = sdp.fetchAfter(lastTime); if (objs != null) { for (int i = 0; i < objs.size(); i++) { SearchEnabled obj = (SearchEnabled) objs.get(i); SearchProxy.add(obj); if (i > 0 && (i + 1) % 10 == 0) log.info((i + 1) + " document's indexes added."); } saveLastActiveTime(providerClass, new Date()); if (objs.size() > 0) { log.info(objs.size() + " documents writed to disk of " + providerClass); } } else log.warn("fetch data of " + providerClass + " return null"); } catch (Exception e) { log.error("Exception occur when buildIndexes using " + providerClass, e); } finally { HibernateUtils.closeSession(); objs = null; } } /** * ???? * * @param pvdClass * @return * @throws IOException */ private Date getLastActiveTime(String pvdClass) throws IOException { // Date lastTime = null; StringBuffer status_file_uri = new StringBuffer(STATUS_FILE_PATH); status_file_uri.append(pvdClass); status_file_uri.append(".his"); String realPath = context.getRealPath(status_file_uri.toString()); Properties props = new Properties(); FileInputStream fis = null; try { fis = new FileInputStream(realPath); props.load(fis); String s_last_time = props.getProperty(TIME_KEY); return new Date(Long.parseLong(s_last_time)); } catch (FileNotFoundException e) { } catch (NumberFormatException e) { } catch (NullPointerException e) { } finally { props = null; if (fis != null) fis.close(); } return null; } /** * ? * * @param pvdClass * @param time * @throws IOException */ private void saveLastActiveTime(String pvdClass, Date time) throws IOException { StringBuffer status_file_uri = new StringBuffer(STATUS_FILE_PATH); status_file_uri.append(pvdClass); status_file_uri.append(".his"); String realPath = context.getRealPath(status_file_uri.toString()); Properties props = new Properties(); FileOutputStream fos = null; try { props.setProperty(TIME_KEY, String.valueOf(time.getTime())); props.setProperty("LAST_TIME", time.toString()); fos = new FileOutputStream(realPath); props.store(fos, null); } finally { props = null; if (fos != null) { fos.close(); fos = null; } } } private final static String STATUS_FILE_PATH = "/WEB-INF/tmp/"; private final static String TIME_KEY = "LAST_ACTIVITY_TIME"; }