KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > dlog4j > search > SearchEnginePlugIn


1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU Library General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */

16 package dlog4j.search;
17
18 import java.io.File JavaDoc;
19 import java.io.FileInputStream JavaDoc;
20 import java.io.FileOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.util.Date JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Properties JavaDoc;
27
28 import javax.servlet.ServletException JavaDoc;
29
30 import net.sf.hibernate.Query;
31 import net.sf.hibernate.Session;
32
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.lucene.analysis.Analyzer;
37 import org.apache.lucene.analysis.standard.StandardAnalyzer;
38 import org.apache.lucene.document.DateField;
39 import org.apache.lucene.document.Document;
40 import org.apache.lucene.document.Field;
41 import org.apache.lucene.index.IndexWriter;
42 import org.apache.struts.action.PlugIn;
43 import org.apache.struts.action.ActionServlet;
44 import org.apache.struts.config.ModuleConfig;
45
46 import dlog4j.ManagerBase;
47 import dlog4j.formbean.LogForm;
48 import dlog4j.formbean.ReplyForm;
49
50 /**
51  * A search engine daemon using lucene implements struts's plugin
52  * 日记和评论的索引分开两个目录存放
53  * @author Liudong
54  */

55 public class SearchEnginePlugIn implements PlugIn, Runnable JavaDoc{
56
57     /**
58      * analyzer提供了切词的方法。可替换。 建索引和搜索时,应该使用同一个analyzer。
59      */

60     private static Analyzer analyzer;
61     
62     protected static ActionServlet servlet = null;
63     
64     /* properties from plugin's struts-config.xml */
65     protected int activeInterval = 600;
66     protected static String JavaDoc logIndexPath = "/WEB-INF/log_index";
67     protected static String JavaDoc replyIndexPath = "/WEB-INF/reply_index";
68     protected String JavaDoc statusFile = "/WEB-INF/lastActiveTime.sav";
69
70     protected String JavaDoc analyzerClass;
71     private Thread JavaDoc daemon;
72
73     /**
74      * The webapp started.
75      * @see org.apache.struts.action.PlugIn#init(ActionServlet servlet, ModuleConfig config)
76      */

77     public void init(ActionServlet servlet, ModuleConfig config) throws ServletException JavaDoc{
78         SearchEnginePlugIn.servlet = servlet;
79         if(analyzerClass==null)
80             analyzerClass = StandardAnalyzer.class.getName();
81         try{
82             analyzer = (Analyzer)Class.forName(analyzerClass).newInstance();
83         }catch(Exception JavaDoc e){
84             servlet.log("Initialize Analyzer Failed.",e);
85         }
86         daemon = new Thread JavaDoc(this);
87         daemon.setDaemon(true);
88         daemon.start();
89     }
90     /**
91      * The webapp is to be stop.
92      * @see org.apache.struts.action.PlugIn#destroy()
93      */

94     public void destroy() {
95         stop = true;
96         /* wait the daemon to terminal */
97         try {
98             Thread.sleep(1000);
99         }catch(InterruptedException JavaDoc e) {}
100     }
101     /**
102      * 得到日记索引的Writter
103      * @return
104      * @throws IOException
105      */

106     protected IndexWriter getLogIndexWriter() throws IOException JavaDoc{
107         String JavaDoc logPath = getLogIndexPath();
108         File JavaDoc rp = new File JavaDoc(logPath);
109         if(!rp.exists())
110             rp.mkdirs();
111         File JavaDoc segments = new File JavaDoc(logPath + File.separator + "segments");
112         boolean bCreate = !segments.exists();
113         return new IndexWriter(logPath,analyzer,bCreate);
114     }
115     /**
116      * 得到评论索引的Writter
117      * @return
118      * @throws IOException
119      */

120     protected IndexWriter getReplyIndexWriter() throws IOException JavaDoc{
121         String JavaDoc replyPath = getReplyIndexPath();
122         File JavaDoc rp = new File JavaDoc(replyPath);
123         if(!rp.exists())
124             rp.mkdirs();
125         File JavaDoc segments = new File JavaDoc(replyPath + File.separator + "segments");
126         boolean bCreate = !segments.exists();
127         return new IndexWriter(replyPath,analyzer,bCreate);
128     }
129     /**
130      * 构建某个时间戳后的所有日记信息的索引
131      * @param lastLogTime
132      * @return 返回新增日记索引的数目
133      * @throws SQLException
134      */

135     protected int buildLogIndex(IndexWriter writer, LastInfo lastInfo) throws Exception JavaDoc{
136         Session ssn = ManagerBase.getSession();
137         int logCount = 0;
138         try {
139             Date JavaDoc begin = new Date JavaDoc(lastInfo.lastLogTime);
140             String JavaDoc hql = "FROM " + LogForm.class.getName() + " AS log WHERE log.logTime>? ORDER BY log.logTime ASC";
141             Query query = ssn.createQuery(hql);
142             query.setDate(0,new Date JavaDoc(lastInfo.lastLogTime));
143             Iterator JavaDoc logs = query.list().iterator();
144             while(logs.hasNext()) {
145                 LogForm log = (LogForm)logs.next();
146                 if(!log.getLogTime().after(begin) || log.getContent()==null)
147                     continue;
148                 Document doc = new Document();
149                 doc.add(Field.Keyword("logId", Integer.toString(log.getId())));
150                 doc.add(new Field("author", log.getOwnerName(),false,true,false));
151                 doc.add(new Field("siteId", Integer.toString(log.getSite().getId()),false,true,false));
152                 doc.add(new Field("categoryId", Integer.toString(log.getCategoryId()),false,true, false));
153                 doc.add(Field.UnStored("title", StringUtils.deleteWhitespace(log.getTitle())));
154                 doc.add(Field.UnStored("content", log.getContent()));
155                 doc.add(new Field("logDate", DateField.dateToString(log.getLogTime()),false,true,false));
156                 writer.addDocument(doc);
157                 logCount ++;
158                 //保存该日记的时间做为时间戳
159
lastInfo.lastLogTime = log.getLogTime().getTime();
160                 
161             }
162         }finally {
163             ManagerBase.closeSession(ssn);
164         }
165         return logCount;
166     }
167     /**
168      * 构建某个时间戳后的所有评论信息的索引
169      * @param lastLogTime
170      * @return 返回新增评论索引的数目
171      */

172     protected int buildReplyIndex(IndexWriter writer, LastInfo lastInfo) throws Exception JavaDoc{
173         Session ssn = ManagerBase.getSession();
174         int replyCount = 0;
175         try {
176             Date JavaDoc begin = new Date JavaDoc(lastInfo.lastReplyTime);
177             String JavaDoc hql = "FROM " + ReplyForm.class.getName() + " AS r WHERE r.writeTime>? ORDER BY r.writeTime ASC";
178             Query query = ssn.createQuery(hql);
179             query.setDate(0,new Date JavaDoc(lastInfo.lastReplyTime));
180             Iterator JavaDoc replies = query.list().iterator();
181             while(replies.hasNext()) {
182                 ReplyForm reply = (ReplyForm)replies.next();
183                 if(!reply.getWriteTime().after(begin))
184                     continue;
185                 Document doc = new Document();
186                 doc.add(Field.Keyword("replyId", Integer.toString(reply.getId())));
187                 doc.add(Field.Keyword("logId", Integer.toString(reply.getLogId())));
188                 doc.add(new Field("categoryId", Integer.toString(reply.getLog().getCategoryId()),false,true, false));
189                 doc.add(new Field("author", reply.getAuthorName(),false,true,false));
190                 doc.add(new Field("siteId", Integer.toString(reply.getSite().getId()),false,true,false));
191                 doc.add(Field.UnStored("content", reply.getContent()));
192                 doc.add(new Field("replyDate", DateField.dateToString(reply.getWriteTime()),false,true,false));
193                 writer.addDocument(doc);
194                 replyCount++;
195                 //保存该日记的时间做为时间戳
196
lastInfo.lastReplyTime = System.currentTimeMillis();
197                 
198             }
199         }finally {
200             ManagerBase.closeSession(ssn);
201         }
202         return replyCount;
203     }
204     
205     private boolean stop = false;
206     
207     /* 自动创建索引的线程入口
208      * @see java.lang.Runnable#run()
209      */

210     public void run() {
211         Log log = LogFactory.getLog(SearchEnginePlugIn.class);
212         while(!stop) {
213             IndexWriter logWriter = null;
214             IndexWriter replyWriter = null;
215             try {
216                 //Check if need to rebuild index.
217
LastInfo lastInfo = getLastInfo();
218                 //更新日记索引
219
logWriter = getLogIndexWriter();
220                 int lc = buildLogIndex(logWriter,lastInfo);
221                 logWriter.optimize();
222                 log.info("Build "+lc +" log's index success.");
223                 //更新评论索引
224
replyWriter = getReplyIndexWriter();
225                 int rc = buildReplyIndex(replyWriter,lastInfo);
226                 replyWriter.optimize();
227                 log.info("Build "+rc +" reply's index success.");
228                 
229                 saveLastInfo(lastInfo);
230             }catch(Exception JavaDoc e) {
231                 log.error("SearchEnginePlugIn.AutoIndexBuild",e);
232             }catch(Throwable JavaDoc t) {
233                 log.fatal("SearchEnginePlugIn.AutoIndexBuild",t);
234             }finally {
235                 if(logWriter!=null)
236                 try {
237                     logWriter.close();
238                 }catch(Exception JavaDoc e) {}
239                 if(replyWriter!=null)
240                     try {
241                         replyWriter.close();
242                     }catch(Exception JavaDoc e) {}
243                 //wait for next active.
244
try {
245                     int i;
246                     for(i=0;!stop&&i<2400;i++)
247                         Thread.sleep(activeInterval*1000/2400);
248                     if(i<2400)
249                         break;
250                 }catch(Exception JavaDoc e) {
251                     break;
252                 }
253             }
254         }
255         log.info("SearchEnginePlugIn terminal.");
256     }
257     /**
258      * 读取配置信息(最近一次更新日记、评论的时间)
259      * @return
260      * @throws Exception
261      */

262     private LastInfo getLastInfo() throws Exception JavaDoc{
263         File JavaDoc f_status = new File JavaDoc(getStatusFile());
264         Properties JavaDoc p = null;
265         if(f_status.exists()) {
266             InputStream JavaDoc is = null;
267             try {
268                 is = new FileInputStream JavaDoc(f_status);
269                 p = new Properties JavaDoc();
270                 p.load(is);
271             }finally {
272                 if(is!=null)
273                     is.close();
274             }
275         }
276         return new LastInfo(p);
277     }
278     /**
279      * 保存配置信息(最近一次更新日记、评论的时间)
280      * @param props
281      * @throws IOException
282      */

283     private void saveLastInfo(LastInfo props) throws IOException JavaDoc{
284         File JavaDoc f_status = new File JavaDoc(getStatusFile());
285         OutputStream JavaDoc out = null;
286         try {
287             out = new FileOutputStream JavaDoc(f_status);
288             props.getProperties().store(out,"SearchEngine Data Saved.");
289         }finally {
290             if(out!=null)
291                 out.close();
292         }
293     }
294     /**
295      * 配置信息类
296      * @author Liudong
297      */

298     private class LastInfo{
299         public final static String JavaDoc REPLY_KEY = "LAST_REPLY_TIME";
300         public final static String JavaDoc LOG_KEY = "LAST_LOG_TIME";
301         public LastInfo(Properties JavaDoc p) {
302             if(p!=null) {
303                 try {
304                     lastReplyTime = Long.parseLong(p.getProperty(REPLY_KEY,"0"));
305                 }catch(Exception JavaDoc e) {}
306                 try {
307                     lastLogTime = Long.parseLong(p.getProperty(LOG_KEY,"0"));
308                 }catch(Exception JavaDoc e) {}
309             }
310         }
311         public Properties JavaDoc getProperties() {
312             Properties JavaDoc ps = new Properties JavaDoc();
313             ps.setProperty(LOG_KEY,String.valueOf(lastLogTime));
314             ps.setProperty(REPLY_KEY,String.valueOf(lastReplyTime));
315             return ps;
316         }
317         public long lastReplyTime;
318         public long lastLogTime;
319     }
320     
321     /* 以下几个getter/setter方法用于对应PlugIn的配置信息 */
322     public int getActiveInterval() {
323         return activeInterval;
324     }
325     public void setActiveInterval(int activeInterval) {
326         this.activeInterval = activeInterval;
327     }
328     /**
329      * 得到日记索引目录所在的绝对路径
330      * @return
331      */

332     public static String JavaDoc getLogIndexPath() {
333         if(logIndexPath.toUpperCase().startsWith("/WEB-INF"))
334             return servlet.getServletContext().getRealPath(logIndexPath);
335         return logIndexPath;
336     }
337     public void setLogIndexPath(String JavaDoc indexPath) {
338         logIndexPath = indexPath;
339     }
340     /**
341      * 得到评论索引目录所在的绝对路径
342      * @return
343      */

344     public static String JavaDoc getReplyIndexPath() {
345         if(replyIndexPath.toUpperCase().startsWith("/WEB-INF"))
346             return servlet.getServletContext().getRealPath(replyIndexPath);
347         return replyIndexPath;
348     }
349     public void setReplyIndexPath(String JavaDoc indexPath) {
350         replyIndexPath = indexPath;
351     }
352     /**
353      * 得到保存状态信息的文件所在的绝对路径
354      * @return
355      */

356     public String JavaDoc getStatusFile() {
357         if(statusFile.startsWith("/"))
358             return servlet.getServletContext().getRealPath(statusFile);
359         return statusFile;
360     }
361     public void setStatusFile(String JavaDoc statusFile) {
362         this.statusFile = statusFile;
363     }
364     public static Analyzer getAnalyzer() {
365         return analyzer;
366     }
367     public String JavaDoc getAnalyzerClass() {
368         return analyzerClass;
369     }
370     public void setAnalyzerClass(String JavaDoc analyzerClass) {
371         this.analyzerClass = analyzerClass;
372     }
373 }
374
Popular Tags