1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.search.lucene;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.util.concurrent.ConcurrentHashMap;
29 import net.jcip.annotations.Immutable;
30 import net.jcip.annotations.ThreadSafe;
31 import org.apache.lucene.store.Directory;
32 import org.apache.lucene.store.FSDirectory;
33 import org.apache.lucene.store.LockFactory;
34 import org.apache.lucene.store.RAMDirectory;
35 import org.apache.lucene.util.Version;
36 import org.modeshape.common.i18n.I18n;
37 import org.modeshape.common.text.NoOpEncoder;
38 import org.modeshape.common.text.TextEncoder;
39 import org.modeshape.common.util.CheckArg;
40 import org.modeshape.common.util.FileUtil;
41 import org.modeshape.common.util.HashCode;
42 import org.modeshape.common.util.Logger;
43 import org.modeshape.graph.search.SearchEngineException;
44
45
46
47
48 public class LuceneConfigurations {
49
50
51
52
53
54
55 public static final LuceneConfiguration inMemory() {
56 return new RamDirectoryFactory();
57 }
58
59
60
61
62
63
64
65
66
67
68 public static final LuceneConfiguration using( File parent ) {
69 CheckArg.isNotNull(parent, "parent");
70 return new FileSystemDirectoryFromNameFactory(parent);
71 }
72
73
74
75
76
77
78
79
80
81
82
83 public static final LuceneConfiguration using( File parent,
84 LockFactory lockFactory ) {
85 CheckArg.isNotNull(parent, "parent");
86 return new FileSystemDirectoryFromNameFactory(parent, lockFactory);
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100 public static final LuceneConfiguration using( File parent,
101 TextEncoder workspaceNameEncoder,
102 TextEncoder indexNameEncoder ) {
103 CheckArg.isNotNull(parent, "parent");
104 return new FileSystemDirectoryFromNameFactory(parent, workspaceNameEncoder, indexNameEncoder);
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119 public static final LuceneConfiguration using( File parent,
120 LockFactory lockFactory,
121 TextEncoder workspaceNameEncoder,
122 TextEncoder indexNameEncoder ) {
123 CheckArg.isNotNull(parent, "parent");
124 return new FileSystemDirectoryFromNameFactory(parent, lockFactory, workspaceNameEncoder, indexNameEncoder);
125 }
126
127
128
129
130
131
132
133
134 @ThreadSafe
135 protected static abstract class PoolingDirectoryFactory<DirectoryType extends Directory> implements LuceneConfiguration {
136 private final ConcurrentHashMap<IndexId, DirectoryType> directories = new ConcurrentHashMap<IndexId, DirectoryType>();
137
138
139
140
141
142
143 public Directory getDirectory( String workspaceName,
144 String indexName ) throws SearchEngineException {
145 CheckArg.isNotNull(workspaceName, "workspaceName");
146 IndexId id = new IndexId(workspaceName, indexName);
147 DirectoryType result = directories.get(id);
148 if (result == null) {
149 DirectoryType newDirectory = createDirectory(workspaceName, indexName);
150 result = directories.putIfAbsent(id, newDirectory);
151 if (result == null) result = newDirectory;
152 }
153 return result;
154 }
155
156
157
158
159
160
161 public boolean destroyDirectory( String workspaceName,
162 String indexName ) throws SearchEngineException {
163 CheckArg.isNotNull(workspaceName, "workspaceName");
164 IndexId id = new IndexId(workspaceName, indexName);
165 DirectoryType result = directories.remove(id);
166 return result != null ? doDestroy(result) : false;
167 }
168
169
170
171
172
173
174
175
176
177 protected abstract DirectoryType createDirectory( String workspaceName,
178 String indexName ) throws SearchEngineException;
179
180 protected abstract boolean doDestroy( DirectoryType directory ) throws SearchEngineException;
181 }
182
183
184
185
186
187
188 @ThreadSafe
189 public static class RamDirectoryFactory extends PoolingDirectoryFactory<RAMDirectory> {
190 protected RamDirectoryFactory() {
191 }
192
193
194
195
196
197
198 @Override
199 public Version getVersion() {
200 return Version.LUCENE_30;
201 }
202
203 @Override
204 protected RAMDirectory createDirectory( String workspaceName,
205 String indexName ) {
206 return new RAMDirectory();
207 }
208
209
210
211
212
213
214 @Override
215 protected boolean doDestroy( RAMDirectory directory ) throws SearchEngineException {
216 return directory != null;
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 public static class FileSystemDirectoryFromNameFactory extends PoolingDirectoryFactory<FSDirectory> {
232 private final File parentFile;
233 private final LockFactory lockFactory;
234 private final TextEncoder workspaceNameEncoder;
235 private final TextEncoder indexNameEncoder;
236
237
238
239
240
241
242
243
244
245 protected FileSystemDirectoryFromNameFactory( File parent ) {
246 this(parent, null, null, null);
247 }
248
249
250
251
252
253
254
255
256
257
258 protected FileSystemDirectoryFromNameFactory( File parent,
259 LockFactory lockFactory ) {
260 this(parent, lockFactory, null, null);
261 }
262
263
264
265
266
267
268
269
270
271
272
273 protected FileSystemDirectoryFromNameFactory( File parent,
274 TextEncoder workspaceNameEncoder,
275 TextEncoder indexNameEncoder ) {
276 this(parent, null, workspaceNameEncoder, indexNameEncoder);
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290 protected FileSystemDirectoryFromNameFactory( File parent,
291 LockFactory lockFactory,
292 TextEncoder workspaceNameEncoder,
293 TextEncoder indexNameEncoder ) {
294 CheckArg.isNotNull(parent, "parent");
295 this.parentFile = parent;
296 this.lockFactory = lockFactory;
297 this.workspaceNameEncoder = workspaceNameEncoder != null ? workspaceNameEncoder : new NoOpEncoder();
298 this.indexNameEncoder = indexNameEncoder != null ? indexNameEncoder : new NoOpEncoder();
299 }
300
301
302
303
304
305
306 @Override
307 public Version getVersion() {
308 return Version.LUCENE_30;
309 }
310
311 @Override
312 protected FSDirectory createDirectory( String workspaceName,
313 String indexName ) {
314 File workspaceFile = new File(parentFile, workspaceNameEncoder.encode(workspaceName));
315 if (!workspaceFile.exists()) {
316 workspaceFile.mkdirs();
317 } else {
318 if (!workspaceFile.isDirectory()) {
319 I18n msg = LuceneI18n.locationForIndexesIsNotDirectory;
320 throw new SearchEngineException(msg.text(workspaceFile.getAbsolutePath(), workspaceName));
321 }
322 if (!workspaceFile.canRead()) {
323 I18n msg = LuceneI18n.locationForIndexesCannotBeRead;
324 throw new SearchEngineException(msg.text(workspaceFile.getAbsolutePath(), workspaceName));
325 }
326 if (!workspaceFile.canWrite()) {
327 I18n msg = LuceneI18n.locationForIndexesCannotBeWritten;
328 throw new SearchEngineException(msg.text(workspaceFile.getAbsolutePath(), workspaceName));
329 }
330 }
331 File directory = workspaceFile;
332 if (indexName != null) {
333 File indexFile = new File(workspaceFile, indexNameEncoder.encode(indexName));
334 if (!indexFile.exists()) {
335 Logger.getLogger(LuceneConfigurations.class).debug("Creating index folders for the '{0}' workspace at '{1}'",
336 workspaceName,
337 workspaceFile);
338 indexFile.mkdirs();
339 } else {
340 if (!indexFile.isDirectory()) {
341 I18n msg = LuceneI18n.locationForIndexesIsNotDirectory;
342 throw new SearchEngineException(msg.text(indexFile.getAbsolutePath(), workspaceName));
343 }
344 if (!indexFile.canRead()) {
345 I18n msg = LuceneI18n.locationForIndexesCannotBeRead;
346 throw new SearchEngineException(msg.text(indexFile.getAbsolutePath(), workspaceName));
347 }
348 if (!indexFile.canWrite()) {
349 I18n msg = LuceneI18n.locationForIndexesCannotBeWritten;
350 throw new SearchEngineException(msg.text(indexFile.getAbsolutePath(), workspaceName));
351 }
352 }
353 directory = indexFile;
354 }
355 try {
356 Logger.getLogger(LuceneConfigurations.class)
357 .debug("Initializing index files for the '{0}' workspace indexes under '{1}'", workspaceName, workspaceFile);
358 return create(directory, lockFactory);
359 } catch (IOException e) {
360 throw new SearchEngineException(e);
361 }
362 }
363
364
365
366
367
368
369 @Override
370 protected boolean doDestroy( FSDirectory directory ) throws SearchEngineException {
371 File file = directory.getFile();
372 if (file.exists()) {
373 return FileUtil.delete(file);
374 }
375 return false;
376 }
377
378
379
380
381
382
383
384
385
386 protected FSDirectory create( File directory,
387 LockFactory lockFactory ) throws IOException {
388 return FSDirectory.open(directory, lockFactory);
389 }
390 }
391
392 @Immutable
393 protected static final class IndexId {
394 private final String workspaceName;
395 private final String indexName;
396 private final int hc;
397
398 protected IndexId( String workspaceName,
399 String indexName ) {
400 assert workspaceName != null;
401 this.workspaceName = workspaceName;
402 this.indexName = indexName;
403 this.hc = HashCode.compute(this.workspaceName, this.indexName);
404 }
405
406
407
408
409 public String getIndexName() {
410 return indexName;
411 }
412
413
414
415
416 public String getWorkspaceName() {
417 return workspaceName;
418 }
419
420
421
422
423
424
425 @Override
426 public int hashCode() {
427 return hc;
428 }
429
430
431
432
433
434
435 @Override
436 public boolean equals( Object obj ) {
437 if (obj == this) return true;
438 if (obj instanceof IndexId) {
439 IndexId that = (IndexId)obj;
440 if (this.hashCode() != that.hashCode()) return false;
441 if (!this.workspaceName.equals(that.workspaceName)) return false;
442 if (!this.indexName.equals(that.indexName)) return false;
443 return true;
444 }
445 return false;
446 }
447
448
449
450
451
452
453 @Override
454 public String toString() {
455 return indexName != null ? workspaceName + "/" + this.indexName : this.workspaceName;
456 }
457 }
458 }