001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.lucene.engine.store;
018:
019: import java.io.File;
020: import java.io.IOException;
021:
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.apache.lucene.store.Directory;
025: import org.apache.lucene.store.FSDirectory;
026: import org.compass.core.CompassException;
027: import org.compass.core.config.CompassConfigurable;
028: import org.compass.core.config.CompassEnvironment;
029: import org.compass.core.config.CompassSettings;
030: import org.compass.core.engine.SearchEngineException;
031: import org.compass.core.lucene.util.LuceneUtils;
032:
033: /**
034: * A directory store implemented using a file system. Uses Lucene {@link org.apache.lucene.store.FSDirectory}.
035: *
036: * @author kimchy
037: */
038: public class FSDirectoryStore extends AbstractDirectoryStore implements
039: CompassConfigurable {
040:
041: private static final Log log = LogFactory
042: .getLog(FSDirectoryStore.class);
043:
044: public static final String PROTOCOL = "file://";
045:
046: private String indexPath;
047:
048: public void configure(CompassSettings settings)
049: throws CompassException {
050: String connection = settings
051: .getSetting(CompassEnvironment.CONNECTION);
052: if (connection.startsWith(PROTOCOL)) {
053: indexPath = connection.substring(PROTOCOL.length());
054: } else {
055: indexPath = connection;
056: }
057: // Make sure we use the FSDirectory
058: System.setProperty("org.apache.lucene.FSDirectory.class",
059: getFSDirectoryClass());
060: FSDirectory directory;
061: try {
062: directory = FSDirectory.getDirectory(System
063: .getProperty("java.io.tmpdir"));
064: directory.close();
065: } catch (IOException e) {
066: throw new SearchEngineException(
067: "Failed to open the lucene directory", e);
068: }
069: if (!directory.getClass().getName().equals(
070: getFSDirectoryClass())) {
071: throw new SearchEngineException(
072: "Setting type of FS directory is a JVM "
073: + "level setting, you can not set different values within the same JVM");
074: }
075: }
076:
077: public Directory open(String subContext, String subIndex)
078: throws SearchEngineException {
079: try {
080: return FSDirectory.getDirectory(buildPath(subContext,
081: subIndex));
082: } catch (IOException e) {
083: throw new SearchEngineException(
084: "Failed to open directory for path [" + subIndex
085: + "]", e);
086: }
087: }
088:
089: public void deleteIndex(Directory dir, String subContext,
090: String subIndex) throws SearchEngineException {
091: File indexPathFile = new File(buildPath(subContext, subIndex));
092: if (indexPathFile.exists()) {
093: boolean deleted = false;
094: // do this retries for windows...
095: for (int i = 0; i < 10; i++) {
096: deleted = LuceneUtils.deleteDir(indexPathFile);
097: if (deleted) {
098: break;
099: }
100: try {
101: Thread.sleep(500);
102: } catch (InterruptedException e) {
103: // no matter
104: }
105: }
106: if (!deleted) {
107: throw new SearchEngineException(
108: "Failed to delete index directory ["
109: + buildPath(subContext, subIndex) + "]");
110: }
111: }
112: }
113:
114: public void cleanIndex(Directory dir, String subContext,
115: String subIndex) throws SearchEngineException {
116: deleteIndex(dir, subContext, subIndex);
117: }
118:
119: public CopyFromHolder beforeCopyFrom(String subContext,
120: String subIndex, Directory dir)
121: throws SearchEngineException {
122: // first rename the current index directory
123: String path = buildPath(subContext, subIndex);
124: File indexPathFile = new File(path);
125: int count = 0;
126: File renameToIndexPathFile;
127: while (true) {
128: renameToIndexPathFile = new File(path + "-copy" + count++);
129: if (!renameToIndexPathFile.exists()) {
130: break;
131: }
132: }
133: boolean renamed = false;
134: for (int i = 0; i < 10; i++) {
135: renamed = indexPathFile.renameTo(renameToIndexPathFile);
136: if (!renamed) {
137: try {
138: Thread.sleep(500);
139: } catch (InterruptedException e) {
140: // do nothing
141: }
142: } else {
143: break;
144: }
145: }
146: if (!renamed) {
147: throw new SearchEngineException("Failed to rename index ["
148: + path + "] to [" + renameToIndexPathFile.getPath()
149: + "]");
150: }
151:
152: ((FSDirectory) dir).getFile().mkdirs();
153:
154: CopyFromHolder holder = new CopyFromHolder();
155: holder.data = renameToIndexPathFile;
156: return holder;
157: }
158:
159: public void afterSuccessfulCopyFrom(String subContext,
160: String subIndex, CopyFromHolder holder)
161: throws SearchEngineException {
162: File renameToIndexPathFile = (File) holder.data;
163: try {
164: LuceneUtils.deleteDir(renameToIndexPathFile);
165: } catch (Exception e) {
166: log.warn("Failed to delete backup directory", e);
167: }
168: }
169:
170: public void afterFailedCopyFrom(String subContext,
171: CopyFromHolder holder) throws SearchEngineException {
172: // TODO if it fails, try to rename the original one back
173: }
174:
175: protected String buildPath(String subContext, String subIndex) {
176: return indexPath + "/" + subContext + "/" + subIndex;
177: }
178:
179: protected String getFSDirectoryClass() {
180: return "org.apache.lucene.store.FSDirectory";
181: }
182: }
|