001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/search/tags/sakai_2-4-1/search-impl/impl/src/java/org/sakaiproject/search/index/impl/FSIndexStorage.java $
003: * $Id: FSIndexStorage.java 29635 2007-04-26 14:44:09Z ajpoland@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.search.index.impl;
021:
022: import java.io.File;
023: import java.io.FileNotFoundException;
024: import java.io.IOException;
025: import java.util.ArrayList;
026: import java.util.Date;
027: import java.util.List;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.apache.lucene.analysis.Analyzer;
032: import org.apache.lucene.document.Document;
033: import org.apache.lucene.document.Field;
034: import org.apache.lucene.index.IndexReader;
035: import org.apache.lucene.index.IndexWriter;
036: import org.apache.lucene.search.IndexSearcher;
037: import org.apache.lucene.store.FSDirectory;
038: import org.sakaiproject.search.api.SearchService;
039: import org.sakaiproject.search.index.AnalyzerFactory;
040: import org.sakaiproject.search.index.IndexStorage;
041:
042: /**
043: * A local only filestore implementation. This is a simple IndexImplementation
044: * that performs all its indexing in a single, unoptimzed segment on the local
045: * filesystem
046: * @author ieb
047: *
048: */
049: public class FSIndexStorage implements IndexStorage {
050: private static Log log = LogFactory.getLog(FSIndexStorage.class);
051:
052: protected String searchIndexDirectory = "searchindex";
053:
054: protected AnalyzerFactory analyzerFactory = null;
055:
056: protected boolean recoverCorruptedIndex = false;
057:
058: private long lastUpdate = System.currentTimeMillis();
059:
060: private boolean diagnostics;
061:
062: public void init() {
063:
064: }
065:
066: public void doPreIndexUpdate() throws IOException {
067: log.debug("Starting process List on " + searchIndexDirectory);
068: File f = new File(searchIndexDirectory);
069: if (!f.exists()) {
070: f.mkdirs();
071: log.debug("Indexing in " + f.getAbsolutePath());
072: }
073:
074: if (IndexReader.isLocked(searchIndexDirectory)) {
075: // this could be dangerous, I am assuming that
076: // the locking mechanism implemented here is
077: // robust and
078: // already prevents multiple modifiers.
079: // A more
080:
081: IndexReader.unlock(FSDirectory.getDirectory(
082: searchIndexDirectory, true));
083: log
084: .warn("Unlocked Lucene Directory for update, hope this is Ok");
085: }
086: }
087:
088: public IndexReader getIndexReader() throws IOException {
089: return IndexReader.open(searchIndexDirectory);
090: }
091:
092: public IndexWriter getIndexWriter(boolean create)
093: throws IOException {
094: return new IndexWriter(searchIndexDirectory, getAnalyzer(),
095: create);
096: }
097:
098: public void doPostIndexUpdate() throws IOException {
099: lastUpdate = System.currentTimeMillis();
100:
101: }
102:
103: /**
104: * @return Returns the searchIndexDirectory.
105: */
106: public String getSearchIndexDirectory() {
107: return searchIndexDirectory;
108: }
109:
110: public IndexSearcher getIndexSearcher() throws IOException {
111: IndexSearcher indexSearcher = null;
112: try {
113: long reloadStart = System.currentTimeMillis();
114: File indexDirectoryFile = new File(searchIndexDirectory);
115: if (!indexDirectoryFile.exists()) {
116: indexDirectoryFile.mkdirs();
117: }
118:
119: indexSearcher = new IndexSearcher(searchIndexDirectory);
120: if (indexSearcher == null) {
121: log.warn("No search Index exists at this time");
122:
123: }
124: long reloadEnd = System.currentTimeMillis();
125: if (diagnostics) {
126: log.info("Reload Complete "
127: + indexSearcher.getIndexReader().numDocs()
128: + " in " + (reloadEnd - reloadStart));
129: }
130:
131: } catch (FileNotFoundException e) {
132: log.error("There has been a major poblem with the"
133: + " Search Index which has become corrupted ", e);
134: if (doIndexRecovery()) {
135: indexSearcher = new IndexSearcher(searchIndexDirectory);
136: }
137: } catch (IOException e) {
138: log.error("There has been a major poblem with the "
139: + "Search Index which has become corrupted", e);
140: if (doIndexRecovery()) {
141: indexSearcher = new IndexSearcher(searchIndexDirectory);
142: }
143: }
144: return indexSearcher;
145: }
146:
147: protected boolean doIndexRecovery() throws IOException {
148: if (recoverCorruptedIndex) {
149: IndexWriter iw = getIndexWriter(true);
150: Document doc = new Document();
151: String message = "Index Recovery performed on "
152: + (new Date()).toString();
153: doc.add(new Field(SearchService.FIELD_CONTENTS, message,
154: Field.Store.NO, Field.Index.TOKENIZED));
155: iw.addDocument(doc);
156: iw.close();
157: log.error("Sucess fully recoverd From a corrupted index, "
158: + "the index will be empty and require a "
159: + "complete rebuild");
160: return true;
161: }
162: return false;
163: }
164:
165: public boolean indexExists() {
166: return IndexReader.indexExists(searchIndexDirectory);
167: }
168:
169: /**
170: * @return Returns the analyzerFactory.
171: */
172: public AnalyzerFactory getAnalyzerFactory() {
173: return analyzerFactory;
174: }
175:
176: /**
177: * @param analyzerFactory
178: * The analyzerFactory to set.
179: */
180: public void setAnalyzerFactory(AnalyzerFactory analyzerFactory) {
181: this .analyzerFactory = analyzerFactory;
182: }
183:
184: public Analyzer getAnalyzer() {
185: return analyzerFactory.newAnalyzer();
186: }
187:
188: /**
189: * @return Returns the recoverCorruptedIndex.
190: */
191: public boolean isRecoverCorruptedIndex() {
192: return recoverCorruptedIndex;
193: }
194:
195: /**
196: * @param recoverCorruptedIndex
197: * The recoverCorruptedIndex to set.
198: */
199: public void setRecoverCorruptedIndex(boolean recoverCorruptedIndex) {
200: log.info("Using FSIndexStorage, storing the index "
201: + "on the local file system in " + searchIndexDirectory
202: + " if the index is corrupted recovery will "
203: + (recoverCorruptedIndex ? "" : "NOT ")
204: + " be automatic");
205: this .recoverCorruptedIndex = recoverCorruptedIndex;
206: }
207:
208: public void setLocation(String location) {
209: searchIndexDirectory = location;
210:
211: }
212:
213: public long getLastUpdate() {
214: // not really relevant in the non cluster environment
215: return lastUpdate;
216: }
217:
218: public List getSegmentInfoList() {
219: List l = new ArrayList();
220: l
221: .add(new Object[] {
222: "Index Segment Info is not implemented for Local file system index stores",
223: "", "" });
224: return l;
225: }
226:
227: public void closeIndexReader(IndexReader indexReader)
228: throws IOException {
229: if (indexReader != null) {
230: indexReader.close();
231: }
232: }
233:
234: public void closeIndexWriter(IndexWriter indexWrite)
235: throws IOException {
236: if (indexWrite != null) {
237: indexWrite.close();
238: }
239:
240: }
241:
242: public boolean isMultipleIndexers() {
243: return false;
244: }
245:
246: public void closeIndexSearcher(IndexSearcher indexSearcher) {
247: IndexReader indexReader = indexSearcher.getIndexReader();
248: boolean closedAlready = false;
249: try {
250: if (indexReader != null) {
251: indexReader.close();
252: closedAlready = true;
253: }
254: } catch (Exception ex) {
255: log
256: .error("Failed to close Index Reader "
257: + ex.getMessage());
258: }
259: try {
260: indexSearcher.close();
261: } catch (Exception ex) {
262: if (closedAlready) {
263: log.debug("Failed to close Index Searcher "
264: + ex.getMessage());
265: } else {
266: log.error("Failed to close Index Searcher "
267: + ex.getMessage());
268: }
269:
270: }
271: }
272:
273: /* (non-Javadoc)
274: * @see org.sakaiproject.search.api.Diagnosable#disableDiagnostics()
275: */
276: public void disableDiagnostics() {
277: diagnostics = false;
278: }
279:
280: /* (non-Javadoc)
281: * @see org.sakaiproject.search.api.Diagnosable#enableDiagnostics()
282: */
283: public void enableDiagnostics() {
284: diagnostics = true;
285: }
286:
287: /* (non-Javadoc)
288: * @see org.sakaiproject.search.api.Diagnosable#hasDiagnostics()
289: */
290: public boolean hasDiagnostics() {
291: return diagnostics;
292: }
293:
294: /* (non-Javadoc)
295: * @see org.sakaiproject.search.index.IndexStorage#centralIndexExists()
296: */
297: public boolean centralIndexExists() {
298: return indexExists();
299: }
300:
301: }
|