File Source: IndexManagerImpl.java
/*
P/P * Method: org.apache.roller.weblogger.business.search.IndexManagerImpl$1__static_init
*/
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.business.search;
20
21 import java.io.File;
22 import java.io.IOException;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.apache.lucene.analysis.Analyzer;
27 import org.apache.lucene.analysis.standard.StandardAnalyzer;
28 import org.apache.lucene.index.IndexReader;
29 import org.apache.lucene.index.IndexWriter;
30 import org.apache.lucene.store.Directory;
31 import org.apache.lucene.store.FSDirectory;
32 import org.apache.lucene.store.RAMDirectory;
33 import org.apache.roller.weblogger.WebloggerException;
34 import org.apache.roller.weblogger.business.*;
35 import org.apache.roller.weblogger.business.search.operations.AddEntryOperation;
36 import org.apache.roller.weblogger.business.search.operations.IndexOperation;
37 import org.apache.roller.weblogger.business.search.operations.ReIndexEntryOperation;
38 import org.apache.roller.weblogger.business.search.operations.RebuildWebsiteIndexOperation;
39 import org.apache.roller.weblogger.business.search.operations.RemoveEntryOperation;
40 import org.apache.roller.weblogger.business.search.operations.RemoveWebsiteIndexOperation;
41 import org.apache.roller.weblogger.business.search.operations.WriteToIndexOperation;
42 import org.apache.roller.weblogger.pojos.WeblogEntry;
43 import org.apache.roller.weblogger.pojos.Weblog;
44
45 import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
46 import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
47 import org.apache.roller.weblogger.config.WebloggerConfig;
48 import org.apache.commons.lang.StringUtils;
49
50
51 /**
52 * Lucene implementation of IndexManager. This is the central entry point
53 * into the Lucene searching API.
54 * @author Mindaugas Idzelis (min@idzelis.com)
55 * @author mraible (formatting and making indexDir configurable)
56 */
57 @com.google.inject.Singleton
58 public class IndexManagerImpl implements IndexManager {
59 //~ Static fields/initializers
60 // =============================================
61
62 private IndexReader reader;
63 private final Weblogger roller;
64
/*
P/P * Method: org.apache.roller.weblogger.business.search.IndexManagerImpl__static_init
*
* Presumptions:
* org.apache.commons.logging.LogFactory:getFactory(...)@65 != null
*
* Postconditions:
* init'ed(mLogger)
*/
65 static Log mLogger = LogFactory.getFactory().getInstance(
66 IndexManagerImpl.class);
67
68 //~ Instance fields
69 // ========================================================
70
71 private boolean searchEnabled = true;
72
73 File indexConsistencyMarker;
74
75 private boolean useRAMIndex = false;
76
77 private RAMDirectory fRAMindex;
78
79 private String indexDir = null;
80
81 private boolean inconsistentAtStartup = false;
82
83 private ReadWriteLock rwl = new WriterPreferenceReadWriteLock();
84
85 //~ Constructors
86 // ===========================================================
87
88 /**
89 * Creates a new lucene index manager. This should only be created once.
90 * Creating the index manager more than once will definately result in
91 * errors. The preferred way of getting an index is through the
92 * RollerContext.
93 *
94 * @param indexDir -
95 * the path to the index directory
96 */
97 @com.google.inject.Inject
/*
P/P * Method: void org.apache.roller.weblogger.business.search.IndexManagerImpl(Weblogger)
*
* Preconditions:
* mLogger != null
* org/apache/roller/weblogger/config/WebloggerConfig.config != null
* org/apache/roller/weblogger/config/WebloggerConfig.log != null
*
* Presumptions:
* init'ed(java.io.File.separator)
* init'ed(java.io.File.separatorChar)
*
* Postconditions:
* this.inconsistentAtStartup == 0
* this.useRAMIndex == 0
* this.indexConsistencyMarker == &new File(IndexManagerImpl#5)
* this.indexDir != null
* this.roller == roller
* init'ed(this.roller)
* this.rwl == &new WriterPreferenceReadWriteLock(IndexManagerImpl#1)
* init'ed(this.searchEnabled)
* new File(IndexManagerImpl#5) num objects == 1
* new WriterPreferenceReadWriteLock(IndexManagerImpl#1) num objects == 1
*
* Test Vectors:
* java.lang.String:equalsIgnoreCase(...)@103: {0}, {1}
*/
98 protected IndexManagerImpl(Weblogger roller) {
99 this.roller = roller;
100
101 // check config to see if the internal search is enabled
102 String enabled = WebloggerConfig.getProperty("search.enabled");
103 if("false".equalsIgnoreCase(enabled))
104 this.searchEnabled = false;
105
106 // we also need to know what our index directory is
107 // Note: system property expansion is now handled by WebloggerConfig
108 String searchIndexDir = WebloggerConfig.getProperty("search.index.dir");
+ 109 this.indexDir = searchIndexDir.replace('/', File.separatorChar);
110
111 // a little debugging
112 mLogger.info("search enabled: " + this.searchEnabled);
113 mLogger.info("index dir: " + this.indexDir);
114
115 String test = indexDir + File.separator + ".index-inconsistent";
116 indexConsistencyMarker = new File(test);
117 }
118
119
120 /**
121 * @inheritDoc
122 */
123 public void initialize() throws InitializationException {
124
125 // only initialize the index if search is enabled
/*
P/P * Method: void initialize()
*
* Preconditions:
* init'ed(this.searchEnabled)
* (soft) mLogger != null
* (soft) init'ed(this.inconsistentAtStartup)
* (soft) this.indexConsistencyMarker != null
* (soft) init'ed(this.indexDir)
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.useRAMIndex)
*
* Postconditions:
* this.fRAMindex == One-of{old this.fRAMindex, &new RAMDirectory(initialize#2), &new RAMDirectory(initialize#3)}
* (soft) init'ed(this.inconsistentAtStartup)
* new RAMDirectory(initialize#2) num objects <= 1
* new RAMDirectory(initialize#3) num objects <= 1
*
* Test Vectors:
* this.searchEnabled: {0}, {1}
* this.useRAMIndex: {0}, {1}
* java.io.File:exists(...)@133: {0}, {1}
* java.io.File:exists(...)@139: {1}, {0}
* org.apache.lucene.index.IndexReader:indexExists(...)@288: {0}, {1}
*/
126 if (this.searchEnabled) {
127
128 // 1. If inconsistency marker exists.
129 // Delete index
130 // 2. if we're using RAM index
131 // load ram index wrapper around index
132 //
133 if (indexConsistencyMarker.exists()) {
134 getFSDirectory(true);
135 inconsistentAtStartup = true;
136 } else {
137 try {
138 File makeIndexDir = new File(indexDir);
139 if (!makeIndexDir.exists()) {
140 makeIndexDir.mkdirs();
141 inconsistentAtStartup = true;
142 }
143 indexConsistencyMarker.createNewFile();
144 } catch (IOException e) {
145 mLogger.error(e);
146 }
147 }
148
149 if (indexExists()) {
150 if (useRAMIndex) {
151 Directory filesystem = getFSDirectory(false);
152
153 try {
154 fRAMindex = new RAMDirectory(filesystem);
155 } catch (IOException e) {
156 mLogger.error("Error creating in-memory index", e);
157 }
158 }
159 } else {
160 if (useRAMIndex) {
161 fRAMindex = new RAMDirectory();
162 createIndex(fRAMindex);
163 } else {
164 createIndex(getFSDirectory(true));
165 }
166 }
167
168 if (isInconsistentAtStartup()) {
169 mLogger.info(
170 "Index was inconsistent. Rebuilding index in the background...");
171 try {
172 rebuildWebsiteIndex();
173 } catch (WebloggerException e) {
174 mLogger.error("ERROR: scheduling re-index operation");
175 }
176 }
177 }
178
179 }
180
181
182 //~ Methods
183 // ================================================================
184
185 public void rebuildWebsiteIndex() throws WebloggerException {
/*
P/P * Method: void rebuildWebsiteIndex()
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
186 scheduleIndexOperation(
187 new RebuildWebsiteIndexOperation(roller, this, null));
188 }
189
190 public void rebuildWebsiteIndex(Weblog website) throws WebloggerException {
/*
P/P * Method: void rebuildWebsiteIndex(Weblog)
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
191 scheduleIndexOperation(
192 new RebuildWebsiteIndexOperation(roller, this, website));
193 }
194
195 public void removeWebsiteIndex(Weblog website) throws WebloggerException {
/*
P/P * Method: void removeWebsiteIndex(Weblog)
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
196 scheduleIndexOperation(
197 new RemoveWebsiteIndexOperation(roller, this, website));
198 }
199
200 public void addEntryIndexOperation(WeblogEntry entry) throws WebloggerException {
/*
P/P * Method: void addEntryIndexOperation(WeblogEntry)
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
201 AddEntryOperation addEntry = new AddEntryOperation(roller, this, entry);
202 scheduleIndexOperation(addEntry);
203 }
204
205 public void addEntryReIndexOperation(WeblogEntry entry) throws WebloggerException {
/*
P/P * Method: void addEntryReIndexOperation(WeblogEntry)
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
206 ReIndexEntryOperation reindex = new ReIndexEntryOperation(roller, this, entry);
207 scheduleIndexOperation(reindex);
208 }
209
210 public void removeEntryIndexOperation(WeblogEntry entry) throws WebloggerException {
/*
P/P * Method: void removeEntryIndexOperation(WeblogEntry)
*
* Preconditions:
* (soft) mLogger != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*/
211 RemoveEntryOperation removeOp = new RemoveEntryOperation(roller, this, entry);
212 executeIndexOperationNow(removeOp);
213 }
214
215 public ReadWriteLock getReadWriteLock() {
/*
P/P * Method: ReadWriteLock getReadWriteLock()
*
* Preconditions:
* init'ed(this.rwl)
*
* Postconditions:
* return_value == this.rwl
* init'ed(return_value)
*/
216 return rwl;
217 }
218
219 public boolean isInconsistentAtStartup() {
/*
P/P * Method: bool isInconsistentAtStartup()
*
* Preconditions:
* init'ed(this.inconsistentAtStartup)
*
* Postconditions:
* return_value == this.inconsistentAtStartup
* init'ed(return_value)
*/
220 return inconsistentAtStartup;
221 }
222
223 /**
224 * This is the analyzer that will be used to tokenize comment text.
225 *
226 * @return Analyzer to be used in manipulating the database.
227 */
228 public static final Analyzer getAnalyzer() {
/*
P/P * Method: Analyzer getAnalyzer()
*
* Postconditions:
* return_value == &new StandardAnalyzer(getAnalyzer#1)
* new StandardAnalyzer(getAnalyzer#1) num objects == 1
*/
229 return new StandardAnalyzer();
230 }
231
232 private void scheduleIndexOperation(final IndexOperation op) {
233 try {
234 // only if search is enabled
/*
P/P * Method: void scheduleIndexOperation(IndexOperation)
*
* Preconditions:
* (soft) mLogger != null
* (soft) op != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*
* Presumptions:
* java.lang.Object:getClass(...)@236 != null
*
* Test Vectors:
* this.searchEnabled: {0}, {1}
*/
235 if(this.searchEnabled) {
236 mLogger.debug("Starting scheduled index operation: "+op.getClass().getName());
237 roller.getThreadManager().executeInBackground(op);
238 }
239 } catch (InterruptedException e) {
240 mLogger.error("Error executing operation", e);
241 }
242 }
243
244 /**
245 * @param search
246 */
247 public void executeIndexOperationNow(final IndexOperation op) {
248 try {
249 // only if search is enabled
/*
P/P * Method: void executeIndexOperationNow(IndexOperation)
*
* Preconditions:
* (soft) mLogger != null
* (soft) op != null
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*
* Presumptions:
* java.lang.Object:getClass(...)@251 != null
*
* Test Vectors:
* this.searchEnabled: {0}, {1}
*/
250 if(this.searchEnabled) {
251 mLogger.debug("Executing index operation now: "+op.getClass().getName());
252 roller.getThreadManager().executeInForeground(op);
253 }
254 } catch (InterruptedException e) {
255 mLogger.error("Error executing operation", e);
256 }
257 }
258
259 public synchronized void resetSharedReader() {
/*
P/P * Method: void resetSharedReader()
*
* Postconditions:
* this.reader == null
*/
260 reader = null;
261 }
262 public synchronized IndexReader getSharedIndexReader() {
/*
P/P * Method: IndexReader getSharedIndexReader()
*
* Preconditions:
* init'ed(this.reader)
* (soft) mLogger != null
* (soft) init'ed(this.fRAMindex)
* (soft) init'ed(this.indexDir)
* (soft) init'ed(this.useRAMIndex)
*
* Postconditions:
* init'ed(return_value)
* this.reader == return_value
*
* Test Vectors:
* this.reader: Inverse{null}, Addr_Set{null}
*/
263 if (reader == null) {
264 try {
265 reader = IndexReader.open(getIndexDirectory());
266 } catch (IOException e) {
267 }
268 }
269 return reader;
270 }
271
272 /**
273 * Get the directory that is used by the lucene index. This method will
274 * return null if there is no index at the directory location. If we are
275 * using a RAM index, the directory will be a ram directory.
276 *
277 * @return Directory The directory containing the index, or null if error.
278 */
279 public Directory getIndexDirectory() {
/*
P/P * Method: Directory getIndexDirectory()
*
* Preconditions:
* init'ed(this.useRAMIndex)
* (soft) mLogger != null
* (soft) init'ed(this.fRAMindex)
* (soft) init'ed(this.indexDir)
*
* Postconditions:
* init'ed(return_value)
*
* Test Vectors:
* this.useRAMIndex: {0}, {1}
*/
280 if (useRAMIndex) {
281 return fRAMindex;
282 } else {
283 return getFSDirectory(false);
284 }
285 }
286
287 private boolean indexExists() {
/*
P/P * Method: bool indexExists()
*
* Preconditions:
* init'ed(this.indexDir)
*
* Postconditions:
* init'ed(return_value)
*/
288 return IndexReader.indexExists(indexDir);
289 }
290
291 Directory getFSDirectory(boolean delete) {
/*
P/P * Method: Directory getFSDirectory(bool)
*
* Preconditions:
* (soft) mLogger != null
* (soft) init'ed(this.indexDir)
*
* Postconditions:
* init'ed(return_value)
*/
292 Directory directory = null;
293
294 try {
295 directory = FSDirectory.getDirectory(indexDir, delete);
296 } catch (IOException e) {
297 mLogger.error("Problem accessing index directory", e);
298 }
299
300 return directory;
301 }
302
303 private void createIndex(Directory dir) {
/*
P/P * Method: void createIndex(Directory)
*
* Preconditions:
* (soft) mLogger != null
*/
304 IndexWriter writer = null;
305
306 try {
307 writer = new IndexWriter(dir, IndexManagerImpl.getAnalyzer(), true);
308 } catch (IOException e) {
309 mLogger.error("Error creating index", e);
310 } finally {
311 try {
312 if (writer != null) {
313 writer.close();
314 }
315 } catch (IOException e) {
316 }
317 }
318 }
319
320 private IndexOperation getSaveIndexOperation() {
/*
P/P * Method: IndexOperation getSaveIndexOperation()
*
* Postconditions:
* return_value == &new IndexManagerImpl$1(getSaveIndexOperation#1)
* new IndexManagerImpl$1(getSaveIndexOperation#1) num objects == 1
* return_value.manager == this
* return_value.manager != null
*/
321 return new WriteToIndexOperation(this) {
322 public void doRun() {
/*
P/P * Method: void doRun()
*
* Preconditions:
* init'ed(this.useRAMIndex)
* (soft) org/apache/roller/weblogger/business/search/IndexManagerImpl.mLogger != null
* (soft) init'ed(this.fRAMindex)
* (soft) this.indexConsistencyMarker != null
* (soft) init'ed(this.indexDir)
*/
323 Directory dir = getIndexDirectory();
324 Directory fsdir = getFSDirectory(true);
325
326 IndexWriter writer = null;
327
328 try {
329 writer = new IndexWriter(fsdir, IndexManagerImpl
330 .getAnalyzer(), true);
331
332 writer.addIndexes(new Directory[] { dir });
333 indexConsistencyMarker.delete();
334 } catch (IOException e) {
335 mLogger.error("Problem saving index to disk", e);
336
337 // Delete the directory, since there was a problem saving
338 // the RAM contents
339 getFSDirectory(true);
340 } finally {
341 try {
342 if (writer != null)
343 writer.close();
344 } catch (IOException e1) {
345 mLogger.warn("Unable to close IndexWriter.");
346 }
347 }
348
349 }
350 };
351 }
352
353 public void release() {
354 // no-op
/*
P/P * Method: void release()
*/
355 }
356
357 public void shutdown() {
/*
P/P * Method: void shutdown()
*
* Preconditions:
* init'ed(this.useRAMIndex)
* (soft) mLogger != null
* (soft) this.indexConsistencyMarker != null
* (soft) init'ed(this.reader)
* (soft) this.roller != null
* (soft) this.roller.threadManager != null
* (soft) this.roller.threadManager.serviceScheduler != null
* (soft) init'ed(this.searchEnabled)
*
* Test Vectors:
* this.reader: Addr_Set{null}, Inverse{null}
* this.useRAMIndex: {0}, {1}
*/
358 if (useRAMIndex) {
359 scheduleIndexOperation(getSaveIndexOperation());
360 } else {
361 indexConsistencyMarker.delete();
362 }
363
364 try {
365 if (reader != null)
366 reader.close();
367 } catch (IOException e) {
368 // won't happen, since it was
369 }
370 }
371
372 }
SofCheck Inspector Build Version : 2.18479
| IndexManagerImpl.java |
2009-Jan-02 14:25:20 |
| IndexManagerImpl.class |
2009-Sep-04 03:12:32 |
| IndexManagerImpl$1.class |
2009-Sep-04 03:12:32 |