KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > roller > business > IndexManagerImpl


1 /*
2  * Created on Jul 18, 2003
3  *
4  * Authored by: Mindaugas Idzelis (min@idzelis.com)
5  */

6 package org.roller.business;
7
8 import java.io.File JavaDoc;
9 import java.io.IOException JavaDoc;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.apache.lucene.analysis.Analyzer;
14 import org.apache.lucene.analysis.standard.StandardAnalyzer;
15 import org.apache.lucene.index.IndexReader;
16 import org.apache.lucene.index.IndexWriter;
17 import org.apache.lucene.store.Directory;
18 import org.apache.lucene.store.FSDirectory;
19 import org.apache.lucene.store.RAMDirectory;
20 import org.roller.RollerException;
21 import org.roller.business.search.operations.AddEntryOperation;
22 import org.roller.business.search.operations.IndexOperation;
23 import org.roller.business.search.operations.ReIndexEntryOperation;
24 import org.roller.business.search.operations.RebuildUserIndexOperation;
25 import org.roller.business.search.operations.RemoveEntryOperation;
26 import org.roller.business.search.operations.RemoveUserIndexOperation;
27 import org.roller.business.search.operations.WriteToIndexOperation;
28 import org.roller.model.IndexManager;
29 import org.roller.pojos.UserData;
30 import org.roller.pojos.WeblogEntryData;
31
32 import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
33 import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
34 import org.roller.config.RollerConfig;
35 import org.roller.model.RollerFactory;
36 import org.roller.util.StringUtils;
37
38 /**
39  * Lucene implementation of IndexManager. This is the central entry point into the Lucene
40  * searching API.
41  * @author aim4min
42  * @author mraible (formatting and making indexDir configurable)
43  */

44 public class IndexManagerImpl implements IndexManager
45 {
46     //~ Static fields/initializers
47
// =============================================
48

49     private IndexReader reader;
50
51     static Log mLogger = LogFactory.getFactory().getInstance(
52             IndexManagerImpl.class);
53
54     //~ Instance fields
55
// ========================================================
56

57     private boolean searchEnabled = true;
58
59     File JavaDoc indexConsistencyMarker;
60
61     private boolean useRAMIndex = false;
62
63     private RAMDirectory fRAMindex;
64
65     private String JavaDoc indexDir = null;
66
67     private boolean inconsistentAtStartup = false;
68
69     private ReadWriteLock rwl = new WriterPreferenceReadWriteLock();
70
71     //~ Constructors
72
// ===========================================================
73

74     /**
75      * Creates a new lucene index manager. This should only be created once.
76      * Creating the index manager more than once will definately result in
77      * errors. The prefered way of getting an index is through the
78      * RollerContext.
79      *
80      * @param indexDir -
81      * the path to the index directory
82      */

83     public IndexManagerImpl()
84     {
85         // check config to see if the internal search is enabled
86
String JavaDoc enabled = RollerConfig.getProperty("search.enabled");
87         if("false".equalsIgnoreCase(enabled))
88             this.searchEnabled = false;
89         
90         // we also need to know what our index directory is
91
String JavaDoc indexDir = RollerConfig.getProperty("search.index.dir");
92         if (indexDir.indexOf("${user.home}") != -1)
93         {
94             indexDir = StringUtils.replace(
95                     indexDir, "${user.home}",
96                     System.getProperty("user.home"));
97         }
98
99         this.indexDir = indexDir.replace('/', File.separatorChar);
100         
101         // a little debugging
102
mLogger.info("search enabled: " + this.searchEnabled);
103         mLogger.info("index dir: " + this.indexDir);
104
105         String JavaDoc test = indexDir + File.separator + ".index-inconsistent";
106         indexConsistencyMarker = new File JavaDoc(test);
107
108         // only setup the index if search is enabled
109
if (this.searchEnabled)
110         {
111             
112             // 1. If inconsistency marker exists.
113
// Delete index
114
// 2. if we're using RAM index
115
// load ram index wrapper around index
116
//
117
if (indexConsistencyMarker.exists())
118             {
119                 getFSDirectory(true);
120                 inconsistentAtStartup = true;
121             }
122             else
123             {
124                 try
125                 {
126                     File JavaDoc makeIndexDir = new File JavaDoc(indexDir);
127                     if (!makeIndexDir.exists())
128                     {
129                         makeIndexDir.mkdirs();
130                         inconsistentAtStartup = true;
131                     }
132                     indexConsistencyMarker.createNewFile();
133                 }
134                 catch (IOException JavaDoc e)
135                 {
136                     mLogger.error(e);
137                 }
138             }
139             
140             if (indexExists())
141             {
142                 if (useRAMIndex)
143                 {
144                     Directory filesystem = getFSDirectory(false);
145                     
146                     try
147                     {
148                         fRAMindex = new RAMDirectory(filesystem);
149                     }
150                     catch (IOException JavaDoc e)
151                     {
152                         mLogger.error("Error creating in-memory index", e);
153                     }
154                 }
155             }
156             else
157             {
158                 if (useRAMIndex)
159                 {
160                     fRAMindex = new RAMDirectory();
161                     createIndex(fRAMindex);
162                 }
163                 else
164                 {
165                     createIndex(getFSDirectory(true));
166                 }
167             }
168             
169             if (isInconsistentAtStartup())
170             {
171                 mLogger.info(
172                     "Index was inconsistent. Rebuilding index in the background...");
173                 try
174                 {
175                     rebuildUserIndex();
176                 }
177                 catch (RollerException e)
178                 {
179                     mLogger.error("ERROR: scheduling re-index operation");
180                 }
181             }
182         }
183     }
184
185     //~ Methods
186
// ================================================================
187

188     public void rebuildUserIndex() throws RollerException
189     {
190         scheduleIndexOperation(
191                 new RebuildUserIndexOperation(this, null));
192     }
193     
194     public void removeUserIndex(UserData user) throws RollerException
195     {
196         scheduleIndexOperation(
197                 new RemoveUserIndexOperation(this, user));
198     }
199     
200     public void addEntryIndexOperation(WeblogEntryData entry) throws RollerException
201     {
202         AddEntryOperation addEntry = new AddEntryOperation(this, entry);
203         scheduleIndexOperation(addEntry);
204     }
205     
206     public void addEntryReIndexOperation(WeblogEntryData entry) throws RollerException
207     {
208         ReIndexEntryOperation reindex = new ReIndexEntryOperation(this, entry);
209         scheduleIndexOperation(reindex);
210     }
211  
212     public void removeEntryIndexOperation(WeblogEntryData entry) throws RollerException
213     {
214         RemoveEntryOperation removeOp = new RemoveEntryOperation(this, entry);
215         executeIndexOperationNow(removeOp);
216     }
217     
218     public ReadWriteLock getReadWriteLock()
219     {
220         return rwl;
221     }
222
223     public boolean isInconsistentAtStartup()
224     {
225         return inconsistentAtStartup;
226     }
227
228     /**
229      * This is the analyzer that will be used to tokenize comment text.
230      *
231      * @return Analyzer to be used in manipulating the database.
232      */

233     public static final Analyzer getAnalyzer()
234     {
235         return new StandardAnalyzer();
236     }
237
238     private void scheduleIndexOperation(final IndexOperation op)
239     {
240         try
241         {
242             // only if search is enabled
243
if(this.searchEnabled) {
244                 mLogger.debug("Starting scheduled index operation: "+op.getClass().getName());
245                 RollerFactory.getRoller().getThreadManager().executeInBackground(op);
246             }
247         }
248         catch (RollerException re)
249         {
250             mLogger.error("Error getting thread manager", re);
251         }
252         catch (InterruptedException JavaDoc e)
253         {
254             mLogger.error("Error executing operation", e);
255         }
256     }
257
258     /**
259      * @param search
260      */

261     public void executeIndexOperationNow(final IndexOperation op)
262     {
263         try
264         {
265             // only if search is enabled
266
if(this.searchEnabled) {
267                 mLogger.debug("Executing index operation now: "+op.getClass().getName());
268                 RollerFactory.getRoller().getThreadManager().executeInForeground(op);
269             }
270         }
271         catch (RollerException re)
272         {
273             mLogger.error("Error getting thread manager", re);
274         }
275         catch (InterruptedException JavaDoc e)
276         {
277             mLogger.error("Error executing operation", e);
278         }
279     }
280
281     public synchronized void resetSharedReader()
282     {
283         reader = null;
284     }
285     public synchronized IndexReader getSharedIndexReader()
286     {
287         if (reader == null)
288         {
289             try
290             {
291                 reader = IndexReader.open(getIndexDirectory());
292             }
293             catch (IOException JavaDoc e)
294             {
295             }
296         }
297         return reader;
298     }
299
300     /**
301      * Get the directory that is used by the lucene index. This method will
302      * return null if there is no index at the directory location. If we are
303      * using a RAM index, the directory will be a ram directory.
304      *
305      * @return Directory The directory containing the index, or null if error.
306      */

307     public Directory getIndexDirectory()
308     {
309         if (useRAMIndex)
310         {
311             return fRAMindex;
312         }
313         else
314         {
315             return getFSDirectory(false);
316         }
317     }
318
319     private boolean indexExists()
320     {
321         return IndexReader.indexExists(indexDir);
322     }
323
324     Directory getFSDirectory(boolean delete)
325     {
326         Directory directory = null;
327
328         try
329         {
330             directory = FSDirectory.getDirectory(indexDir, delete);
331         }
332         catch (IOException JavaDoc e)
333         {
334             mLogger.error("Problem accessing index directory", e);
335         }
336
337         return directory;
338     }
339
340     private void createIndex(Directory dir)
341     {
342         IndexWriter writer = null;
343
344         try
345         {
346             writer = new IndexWriter(dir, IndexManagerImpl.getAnalyzer(), true);
347         }
348         catch (IOException JavaDoc e)
349         {
350             mLogger.error("Error creating index", e);
351         }
352         finally
353         {
354             try
355             {
356                 if (writer != null)
357                 {
358                     writer.close();
359                 }
360             }
361             catch (IOException JavaDoc e)
362             {
363             }
364         }
365     }
366
367     private IndexOperation getSaveIndexOperation()
368     {
369         return new WriteToIndexOperation(this) {
370             public void doRun()
371             {
372                 Directory dir = getIndexDirectory();
373                 Directory fsdir = getFSDirectory(true);
374
375                 IndexWriter writer = null;
376
377                 try
378                 {
379                     writer = new IndexWriter(fsdir, IndexManagerImpl
380                             .getAnalyzer(), true);
381
382                     writer.addIndexes(new Directory[] { dir });
383                     indexConsistencyMarker.delete();
384                 }
385                 catch (IOException JavaDoc e)
386                 {
387                     mLogger.error("Problem saving index to disk", e);
388
389                     // Delete the directory, since there was a problem saving
390
// the RAM contents
391
getFSDirectory(true);
392                 }
393                 finally
394                 {
395                     try
396                     {
397                         if (writer != null)
398                             writer.close();
399                     }
400                     catch (IOException JavaDoc e1)
401                     {
402                         mLogger.warn("Unable to close IndexWriter.");
403                     }
404                 }
405
406             }
407         };
408     }
409
410     public void release()
411     {
412         // no-op
413
}
414     
415     public void shutdown()
416     {
417         if (useRAMIndex)
418         {
419             scheduleIndexOperation(getSaveIndexOperation());
420         }
421         else
422         {
423             indexConsistencyMarker.delete();
424         }
425
426         try
427         {
428             if (reader != null)
429                 reader.close();
430         }
431         catch (IOException JavaDoc e)
432         {
433             // won't happen, since it was
434
}
435     }
436 }
Popular Tags