Index: src/main/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManager.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/directory/DirectoryManager.java (revision 0) @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import org.apache.lucene.store.Directory; +import org.apache.jackrabbit.core.query.lucene.SearchIndex; + +import java.io.IOException; + +/** + * DirectoryManager defines an interface for managing directory + * instances used by the search index. + */ +public interface DirectoryManager { + + /** + * Initializes the directory manager with a reference to the search index. + * + * @param handler the query handler implementation. + * @throws IOException if an error occurs while initializing the directory + * manager. + */ + void init(SearchIndex handler) throws IOException; + + /** + * Checks if there exists a directory with the given name. + * + * @param name the name of a directory. + * @return true if the directory exists; false + * otherwise. + * @throws IOException if an error occurs while looking up directories. + */ + boolean hasDirectory(String name) throws IOException; + + /** + * Gets the directory with the given name. If the directory + * does not yet exist then it will be created. + * + * @param name the name of a directory. + * @return the directory. + * @throws IOException if an error occurs while getting or creating the + * directory. + */ + Directory getDirectory(String name) throws IOException; + + /** + * Returns the names of the currently available directories. + * + * @return names of the currently available directories. + * @throws IOException if an error occurs while retrieving the directory + * names. + */ + String[] getDirectoryNames() throws IOException; + + /** + * Deletes the directory with the given name. + * + * @param name the name of the directory to delete. + * @return true if the directory could be deleted successfully, + * false otherwise. This method also returns + * false when the directory with the given + * name does not exist. + */ + boolean delete(String name); + + /** + * Renames a directory. + * + * @param from the name of the directory to rename. + * @param to the new name for the directory. + * @return true if the directory was successfully renamed. + * Returns false if there is no directory with name + * from or there already exists a directory with name + * to or an error occurs while renaming the directory. + */ + boolean rename(String from, String to); + + /** + * Frees resources associated with this directory manager. + */ + void dispose(); +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\directory\DirectoryManager.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/directory/FSDirectoryManager.java (revision 0) @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.store.NativeFSLockFactory; +import org.apache.jackrabbit.core.query.lucene.SearchIndex; + +import java.io.IOException; +import java.io.File; +import java.io.FileFilter; + +/** + * FSDirectoryManager implements a directory manager for + * {@link FSDirectory} instances. + */ +public class FSDirectoryManager implements DirectoryManager { + + /** + * The base directory. + */ + private File baseDir; + + /** + * {@inheritDoc} + */ + public void init(SearchIndex handler) throws IOException { + baseDir = new File(handler.getPath()); + } + + /** + * {@inheritDoc} + */ + public boolean hasDirectory(String name) throws IOException { + return new File(baseDir, name).exists(); + } + + /** + * {@inheritDoc} + */ + public Directory getDirectory(String name) + throws IOException { + File dir = new File(baseDir, name); + return FSDirectory.getDirectory(dir, new NativeFSLockFactory(dir)); + } + + /** + * {@inheritDoc} + */ + public String[] getDirectoryNames() throws IOException { + File[] dirs = baseDir.listFiles(new FileFilter() { + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + String[] names = new String[dirs.length]; + for (int i = 0; i < dirs.length; i++) { + names[i] = dirs[i].getName(); + } + return names; + } + + /** + * {@inheritDoc} + */ + public boolean delete(String name) { + File directory = new File(baseDir, name); + // trivial if it does not exist anymore + if (!directory.exists()) { + return true; + } + // delete files first + File[] files = directory.listFiles(); + for (int i = 0; i < files.length; i++) { + if (!files[i].delete()) { + return false; + } + } + // now delete directory itself + return directory.delete(); + } + + /** + * {@inheritDoc} + */ + public boolean rename(String from, String to) { + File src = new File(baseDir, from); + File dest = new File(baseDir, to); + return src.renameTo(dest); + } + + /** + * {@inheritDoc} + */ + public void dispose() { + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\directory\FSDirectoryManager.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStream.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStream.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStream.java (revision 0) @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import org.apache.lucene.store.IndexInput; + +import java.io.InputStream; +import java.io.IOException; + +/** + * IndexInputStream implements an {@link InputStream} that wraps + * a lucene {@link IndexInput}. + */ +public class IndexInputStream extends InputStream { + + /** + * The underlying index input. + */ + private final IndexInput in; + + /** + * The length of the index input. + */ + private final long len; + + /** + * The position where the next read will occur. + */ + private long pos; + + /** + * Creates a new index input stream wrapping the given lucene index + * input. + * + * @param input the index input to wrap. + */ + public IndexInputStream(IndexInput input) { + this.in = input; + this.len = input.length(); + } + + /** + * {@inheritDoc} + */ + public int read() throws IOException { + byte[] buf = new byte[1]; + if (read(buf, 0, 1) == -1) { + return -1; + } else { + return buf[0] & 0xff; + } + } + + /** + * {@inheritDoc} + */ + public int read(byte b[], int off, int len) throws IOException { + if (pos >= this.len) { + // EOF + return -1; + } + int num = (int) Math.min(len - off, this.len - pos); + in.readBytes(b, off, num); + pos += num; + return num; + } + + /** + * {@inheritDoc} + *

+ * Closes the underlying index input. + */ + public void close() throws IOException { + in.close(); + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\directory\IndexInputStream.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStream.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStream.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStream.java (revision 0) @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import java.io.OutputStream; +import java.io.IOException; + +import org.apache.lucene.store.IndexOutput; + +/** + * IndexOutputStream wraps an {@link IndexOutput} and exposes it + * as a regular {@link OutputStream}. + */ +public class IndexOutputStream extends OutputStream { + + /** + * The underlying index output. + */ + private final IndexOutput out; + + /** + * Creates a new index output stream and wraps the given + * output. Bytes will always be written at the end of the + * output. + * + * @param output the lucene index output. + * @throws IOException if an error occurs while seeking to the end of the + * index output. + */ + public IndexOutputStream(IndexOutput output) + throws IOException { + this.out = output; + this.out.seek(output.length()); + } + + /** + * {@inheritDoc} + */ + public void write(int b) throws IOException { + byte[] buf = new byte[]{(byte) (b & 0xff)}; + write(buf, 0, 1); + } + + /** + * {@inheritDoc} + */ + public void write(byte b[], int off, int len) throws IOException { + out.writeBytes(b, off, len); + } + + /** + * {@inheritDoc} + *

+ * Flushes the underlying index output. + */ + public void flush() throws IOException { + out.flush(); + } + + /** + * {@inheritDoc} + *

+ * Closes the underlying index output. + */ + public void close() throws IOException { + out.close(); + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\directory\IndexOutputStream.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/directory/RAMDirectoryManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/directory/RAMDirectoryManager.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/directory/RAMDirectoryManager.java (revision 0) @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.jackrabbit.core.query.lucene.SearchIndex; + +import java.util.Map; +import java.util.HashMap; +import java.io.IOException; + +/** + * RAMDirectoryManager implements a directory manager for + * {@link RAMDirectory} instances. + */ +public class RAMDirectoryManager implements DirectoryManager { + + /** + * Map of directories. Key=String(directory name), Value=Directory. + */ + private final Map directories = new HashMap(); + + /** + * {@inheritDoc} + */ + public void init(SearchIndex handler) throws IOException { + } + + /** + * {@inheritDoc} + */ + public boolean hasDirectory(String name) throws IOException { + synchronized (directories) { + return directories.containsKey(name); + } + } + + /** + * {@inheritDoc} + */ + public Directory getDirectory(String name) { + synchronized (directories) { + Directory dir = (Directory) directories.get(name); + if (dir == null) { + dir = new RAMDirectory(); + directories.put(name, dir); + } + return dir; + } + } + + /** + * {@inheritDoc} + */ + public String[] getDirectoryNames() throws IOException { + synchronized (directories) { + return (String[]) directories.keySet().toArray( + new String[directories.size()]); + } + } + + /** + * {@inheritDoc} + */ + public boolean delete(String name) { + synchronized (directories) { + directories.remove(name); + } + return true; + } + + /** + * {@inheritDoc} + */ + public boolean rename(String from, String to) { + synchronized (directories) { + if (directories.containsKey(to)) { + return false; + } + Directory dir = (Directory) directories.remove(from); + if (dir == null) { + return false; + } + directories.put(to, dir); + return true; + } + } + + /** + * {@inheritDoc} + */ + public void dispose() { + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\directory\RAMDirectoryManager.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/IndexInfos.java (working copy) @@ -19,16 +19,17 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.io.File; -import java.io.FileInputStream; import java.io.InputStream; -import java.io.FileOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.HashSet; +import org.apache.lucene.store.Directory; +import org.apache.jackrabbit.core.query.lucene.directory.IndexInputStream; +import org.apache.jackrabbit.core.query.lucene.directory.IndexOutputStream; + /** * Stores a sequence of index names. */ @@ -74,9 +75,10 @@ * * @param dir the directory where to look for the index infos. * @return true if it exists; false otherwise. + * @throws IOException if an error occurs while reading from the directory. */ - boolean exists(File dir) { - return new File(dir, name).exists(); + boolean exists(Directory dir) throws IOException { + return dir.fileExists(name); } /** @@ -94,8 +96,8 @@ * @param dir the directory from where to read the index infos. * @throws IOException if an error occurs. */ - void read(File dir) throws IOException { - InputStream in = new FileInputStream(new File(dir, name)); + void read(Directory dir) throws IOException { + InputStream in = new IndexInputStream(dir.openInput(name)); try { DataInputStream di = new DataInputStream(in); counter = di.readInt(); @@ -115,14 +117,13 @@ * @param dir the directory where to write the index infos. * @throws IOException if an error occurs. */ - void write(File dir) throws IOException { + void write(Directory dir) throws IOException { // do not write if not dirty if (!dirty) { return; } - File nu = new File(dir, name + ".new"); - OutputStream out = new FileOutputStream(nu); + OutputStream out = new IndexOutputStream(dir.createOutput(name + ".new")); try { DataOutputStream dataOut = new DataOutputStream(out); dataOut.writeInt(counter); @@ -134,13 +135,10 @@ out.close(); } // delete old - File old = new File(dir, name); - if (old.exists() && !old.delete()) { - throw new IOException("Unable to delete file: " + old.getAbsolutePath()); + if (dir.fileExists(name)) { + dir.deleteFile(name); } - if (!nu.renameTo(old)) { - throw new IOException("Unable to rename file: " + nu.getAbsolutePath()); - } + dir.renameFile(name + ".new", name); dirty = false; } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueStore.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueStore.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingQueueStore.java (working copy) @@ -16,8 +16,8 @@ */ package org.apache.jackrabbit.core.query.lucene; -import org.apache.jackrabbit.core.fs.FileSystem; -import org.apache.jackrabbit.core.fs.FileSystemException; +import org.apache.jackrabbit.core.query.lucene.directory.IndexInputStream; +import org.apache.lucene.store.Directory; import org.slf4j.LoggerFactory; import org.slf4j.Logger; @@ -31,7 +31,7 @@ /** * IndexingQueueStore implements a store that keeps the uuids of * nodes that are pending in the indexing queue. Until Jackrabbit 1.4 this store - * was also persisted to a {@link FileSystem}. Starting with 1.5 the pending + * was also persisted to disk. Starting with 1.5 the pending * nodes are marked directly in the index with a special field. * See {@link FieldNames#REINDEXING_REQUIRED}. */ @@ -58,33 +58,28 @@ private static final String REMOVE = "REMOVE"; /** - * The UUID Strings of the pending documents. + * Name of the file that contains the indexing queue log. */ - private final Set pending = new HashSet(); + private static final String INDEXING_QUEUE_FILE = "indexing_queue.log"; /** - * The file system from where to read pending document UUIDs. + * The UUID Strings of the pending documents. */ - private final FileSystem fs; + private final Set pending = new HashSet(); /** - * The name of the file for the pending document UUIDs. + * The directory from where to read pending document UUIDs. */ - private final String fileName; + private final Directory dir; /** - * Creates a new IndexingQueueStore using the given file - * system. + * Creates a new IndexingQueueStore using the given directory. * - * @param fs the file system to use. - * @param fileName the name of the file where to write the pending UUIDs - * to. - * @throws FileSystemException if an error ocurrs while reading pending - * UUIDs. + * @param directory the directory to use. + * @throws IOException if an error ocurrs while reading pending UUIDs. */ - IndexingQueueStore(FileSystem fs, String fileName) throws FileSystemException { - this.fs = fs; - this.fileName = fileName; + IndexingQueueStore(Directory directory) throws IOException { + this.dir = directory; readStore(); } @@ -119,11 +114,11 @@ public void close() { if (pending.isEmpty()) { try { - if (fs.exists(fileName)) { - fs.deleteFile(fileName); + if (dir.fileExists(INDEXING_QUEUE_FILE)) { + dir.deleteFile(INDEXING_QUEUE_FILE); } - } catch (FileSystemException e) { - log.warn("unable to delete " + fileName); + } catch (IOException e) { + log.warn("unable to delete " + INDEXING_QUEUE_FILE); } } } @@ -134,39 +129,35 @@ * Reads all pending UUIDs from the file and puts them into {@link * #pending}. * - * @throws FileSystemException if an error occurs while reading. + * @throws IOException if an error occurs while reading. */ - private void readStore() throws FileSystemException { - if (fs.exists(fileName)) { + private void readStore() throws IOException { + if (dir.fileExists(INDEXING_QUEUE_FILE)) { + InputStream in = new IndexInputStream(dir.openInput(INDEXING_QUEUE_FILE)); + BufferedReader reader = new BufferedReader( + new InputStreamReader(in, ENCODING)); try { - InputStream in = fs.getInputStream(fileName); - BufferedReader reader = new BufferedReader( - new InputStreamReader(in, ENCODING)); - try { - String line; - while ((line = reader.readLine()) != null) { - int idx = line.indexOf(' '); - if (idx == -1) { - // invalid line - log.warn("invalid line in {}: {}", fileName, line); + String line; + while ((line = reader.readLine()) != null) { + int idx = line.indexOf(' '); + if (idx == -1) { + // invalid line + log.warn("invalid line in {}: {}", INDEXING_QUEUE_FILE, line); + } else { + String cmd = line.substring(0, idx); + String uuid = line.substring(idx + 1, line.length()); + if (ADD.equals(cmd)) { + pending.add(uuid); + } else if (REMOVE.equals(cmd)) { + pending.remove(uuid); } else { - String cmd = line.substring(0, idx); - String uuid = line.substring(idx + 1, line.length()); - if (ADD.equals(cmd)) { - pending.add(uuid); - } else if (REMOVE.equals(cmd)) { - pending.remove(uuid); - } else { - // invalid line - log.warn("invalid line in {}: {}", fileName, line); - } + // invalid line + log.warn("invalid line in {}: {}", INDEXING_QUEUE_FILE, line); } } - } finally { - in.close(); } - } catch (IOException e) { - throw new FileSystemException(e.getMessage(), e); + } finally { + in.close(); } } } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/IndexMigration.java (working copy) @@ -23,18 +23,16 @@ import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.TermPositions; import org.apache.lucene.index.IndexWriter; -import org.apache.lucene.store.FSDirectory; -import org.apache.lucene.store.NoLockFactory; +import org.apache.lucene.store.Directory; import org.apache.lucene.document.Document; import org.apache.lucene.document.FieldSelector; import org.apache.lucene.document.Fieldable; import org.apache.lucene.document.Field; -import org.apache.jackrabbit.core.fs.local.FileUtil; +import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import java.io.IOException; -import java.io.File; /** * IndexMigration implements a utility that migrates a Jackrabbit @@ -56,11 +54,14 @@ * Checks if the given index needs to be migrated. * * @param index the index to check and migration if needed. - * @param indexDir the directory where the index is stored. + * @param directoryManager the directory manager. * @throws IOException if an error occurs while migrating the index. */ - public static void migrate(PersistentIndex index, File indexDir) throws IOException { - log.debug("Checking {} ...", indexDir.getAbsolutePath()); + public static void migrate(PersistentIndex index, + DirectoryManager directoryManager) + throws IOException { + Directory indexDir = index.getDirectory(); + log.debug("Checking {} ...", indexDir); ReadOnlyIndexReader reader = index.getReadOnlyIndexReader(); try { if (IndexFormatVersion.getVersion(reader).getVersion() >= @@ -87,24 +88,20 @@ } // if we get here then the index must be migrated - log.debug("Index requires migration {}", indexDir.getAbsolutePath()); + log.debug("Index requires migration {}", indexDir); // make sure readers are closed, otherwise the directory // cannot be deleted index.releaseWriterAndReaders(); - File migrationDir = new File(indexDir.getAbsoluteFile().getParentFile(), indexDir.getName() + "_v2.3"); - if (migrationDir.exists()) { - FileUtil.delete(migrationDir); + String migrationName = index.getName() + "_v2.3"; + if (directoryManager.hasDirectory(migrationName)) { + directoryManager.delete(migrationName); } - if (!migrationDir.mkdirs()) { - throw new IOException("failed to create directory " + - migrationDir.getAbsolutePath()); - } - FSDirectory fsDir = FSDirectory.getDirectory(migrationDir, - NoLockFactory.getNoLockFactory()); + + Directory migrationDir = directoryManager.getDirectory(migrationName); try { - IndexWriter writer = new IndexWriter(fsDir, new JackrabbitAnalyzer()); + IndexWriter writer = new IndexWriter(migrationDir, new JackrabbitAnalyzer()); try { IndexReader r = new MigrationIndexReader( IndexReader.open(index.getDirectory())); @@ -118,14 +115,14 @@ writer.close(); } } finally { - fsDir.close(); + migrationDir.close(); } - FileUtil.delete(indexDir); - if (!migrationDir.renameTo(indexDir)) { + directoryManager.delete(index.getName()); + if (!directoryManager.rename(migrationName, index.getName())) { throw new IOException("failed to move migrated directory " + - migrationDir.getAbsolutePath()); + migrationDir); } - log.info("Migrated " + indexDir.getAbsolutePath()); + log.info("Migrated " + index.getName()); } //---------------------------< internal helper >---------------------------- Index: src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/MultiIndex.java (working copy) @@ -17,8 +17,7 @@ package org.apache.jackrabbit.core.query.lucene; import org.apache.jackrabbit.core.NodeId; -import org.apache.jackrabbit.core.fs.FileSystemException; -import org.apache.jackrabbit.core.fs.local.LocalFileSystem; +import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager; import org.apache.jackrabbit.core.state.ItemStateException; import org.apache.jackrabbit.core.state.ItemStateManager; import org.apache.jackrabbit.core.state.NoSuchItemStateException; @@ -35,11 +34,10 @@ import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; +import org.apache.lucene.store.Directory; import javax.jcr.RepositoryException; import java.io.IOException; -import java.io.File; -import java.io.FileFilter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -90,16 +88,6 @@ private static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance(); /** - * Default name of the redo log file - */ - private static final String REDO_LOG = "redo.log"; - - /** - * Name of the file that contains the indexing queue log. - */ - private static final String INDEXING_QUEUE_FILE = "indexing_queue.log"; - - /** * Names of active persistent index directories. */ private final IndexInfos indexNames = new IndexInfos("indexes"); @@ -123,11 +111,16 @@ private final NamespaceMappings nsMappings; /** - * The base filesystem to store the index. + * The directory manager. */ - private final File indexDir; + private final DirectoryManager directoryManager; /** + * The base directory to store the index. + */ + private final Directory indexDir; + + /** * The query handler */ private final SearchIndex handler; @@ -223,24 +216,20 @@ /** * Creates a new MultiIndex. * - * @param indexDir the base file system * @param handler the search handler * @param excludedIDs Set<NodeId> that contains uuids that should not * be indexed nor further traversed. - * @param mapping the namespace mapping to use * @throws IOException if an error occurs */ - MultiIndex(File indexDir, - SearchIndex handler, - Set excludedIDs, - NamespaceMappings mapping) throws IOException { - - this.indexDir = indexDir; + MultiIndex(SearchIndex handler, + Set excludedIDs) throws IOException { + this.directoryManager = handler.getDirectoryManager(); + this.indexDir = directoryManager.getDirectory("."); this.handler = handler; this.cache = new DocNumberCache(handler.getCacheSize()); - this.redoLog = new RedoLog(new File(indexDir, REDO_LOG)); + this.redoLog = new RedoLog(indexDir); this.excludedIDs = new HashSet(excludedIDs); - this.nsMappings = mapping; + this.nsMappings = handler.getNamespaceMappings(); if (indexNames.exists(indexDir)) { indexNames.read(indexDir); @@ -255,34 +244,26 @@ merger.setMergeFactor(handler.getMergeFactor()); merger.setMinMergeDocs(handler.getMinMergeDocs()); - IndexingQueueStore store; - try { - LocalFileSystem fs = new LocalFileSystem(); - fs.setRoot(indexDir); - fs.init(); - store = new IndexingQueueStore(fs, INDEXING_QUEUE_FILE); - } catch (FileSystemException e) { - throw Util.createIOException(e); - } + IndexingQueueStore store = new IndexingQueueStore(indexDir); // initialize indexing queue this.indexingQueue = new IndexingQueue(store); // open persistent indexes for (int i = 0; i < indexNames.size(); i++) { - File sub = new File(indexDir, indexNames.getName(i)); + String name = indexNames.getName(i); // only open if it still exists // it is possible that indexNames still contains a name for // an index that has been deleted, but indexNames has not been // written to disk. - if (!sub.exists()) { - log.debug("index does not exist anymore: " + sub.getAbsolutePath()); + if (!directoryManager.hasDirectory(name)) { + log.debug("index does not exist anymore: " + name); // move on to next index continue; } - PersistentIndex index = new PersistentIndex(indexNames.getName(i), - sub, handler.getTextAnalyzer(), handler.getSimilarity(), - cache, indexingQueue); + PersistentIndex index = new PersistentIndex(name, + handler.getTextAnalyzer(), handler.getSimilarity(), + cache, indexingQueue, directoryManager); index.setMaxMergeDocs(handler.getMaxMergeDocs()); index.setMergeFactor(handler.getMergeFactor()); index.setMinMergeDocs(handler.getMinMergeDocs()); @@ -580,16 +561,14 @@ } // otherwise open / create it - File sub; if (indexName == null) { - sub = newIndexFolder(); - indexName = sub.getName(); - } else { - sub = new File(indexDir, indexName); + do { + indexName = indexNames.newName(); + } while (directoryManager.hasDirectory(indexName)); } - PersistentIndex index = new PersistentIndex(indexName, sub, + PersistentIndex index = new PersistentIndex(indexName, handler.getTextAnalyzer(), handler.getSimilarity(), - cache, indexingQueue); + cache, indexingQueue, directoryManager); index.setMaxMergeDocs(handler.getMaxMergeDocs()); index.setMergeFactor(handler.getMergeFactor()); index.setMinMergeDocs(handler.getMinMergeDocs()); @@ -608,8 +587,10 @@ * * @param indexName the name of the index segment. * @return true if it exists; otherwise false. + * @throws IOException if an error occurs while checking existence of + * directory. */ - synchronized boolean hasIndex(String indexName) { + synchronized boolean hasIndex(String indexName) throws IOException { // check existing for (Iterator it = indexes.iterator(); it.hasNext();) { PersistentIndex idx = (PersistentIndex) it.next(); @@ -618,7 +599,7 @@ } } // check if it exists on disk - return new File(indexDir, indexName).exists(); + return directoryManager.hasDirectory(indexName); } /** @@ -920,19 +901,16 @@ * Enqueues unused segments for deletion in {@link #deletable}. This method * does not synchronize on {@link #deletable}! A caller must ensure that it * is the only one acting on the {@link #deletable} map. + * + * @throws IOException if an error occurs while reading directories. */ - private void enqueueUnusedSegments() { + private void enqueueUnusedSegments() throws IOException { // walk through index segments - File[] segmentDirs = indexDir.listFiles(new FileFilter() { - public boolean accept(File pathname) { - return pathname.isDirectory() && pathname.getName().startsWith("_"); + String[] dirNames = directoryManager.getDirectoryNames(); + for (int i = 0; i < dirNames.length; i++) { + if (dirNames[i].startsWith("_") && !indexNames.contains(dirNames[i])) { + deletable.add(dirNames[i]); } - }); - for (int i = 0; i < segmentDirs.length; i++) { - String name = segmentDirs[i].getName(); - if (!indexNames.contains(name)) { - deletable.add(name); - } } } @@ -1078,8 +1056,7 @@ synchronized (deletable) { for (Iterator it = deletable.iterator(); it.hasNext(); ) { String indexName = (String) it.next(); - File dir = new File(indexDir, indexName); - if (deleteIndex(dir)) { + if (directoryManager.delete(indexName)) { it.remove(); } else { log.info("Unable to delete obsolete index: " + indexName); @@ -1093,55 +1070,17 @@ * in Jackrabbit versions >= 1.5. */ private void removeDeletable() { - File deletable = new File(indexDir, "deletable"); - if (deletable.exists()) { - deletable.delete(); - } - } - - /** - * Deletes the index directory. - * - * @param directory the index directory to delete. - * @return true if the delete was successful, - * false otherwise. - */ - private boolean deleteIndex(File directory) { - // trivial if it does not exist anymore - if (!directory.exists()) { - return true; - } - // delete files first - File[] files = directory.listFiles(); - for (int i = 0; i < files.length; i++) { - if (!files[i].delete()) { - return false; + String fileName = "deletable"; + try { + if (indexDir.fileExists(fileName)) { + indexDir.deleteFile(fileName); } + } catch (IOException e) { + log.warn("Unable to remove file 'deletable'.", e); } - // now delete directory itself - return directory.delete(); } /** - * Returns an new index folder which is empty. - * - * @return the new index folder. - * @throws IOException if the folder cannot be created. - */ - private File newIndexFolder() throws IOException { - // create new index folder. make sure it does not exist - File sub; - do { - sub = new File(indexDir, indexNames.newName()); - } while (sub.exists()); - - if (!sub.mkdir()) { - throw new IOException("Unable to create directory: " + sub.getAbsolutePath()); - } - return sub; - } - - /** * Checks the duration between the last commit to this index and the * current time and flushes the index (if there are changes at all) * if the duration (idle time) is more than {@link SearchIndex#getVolatileIdleTime()} Index: src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/PersistentIndex.java (working copy) @@ -22,12 +22,10 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; -import org.apache.lucene.store.FSDirectory; -import org.apache.lucene.store.NativeFSLockFactory; import org.apache.lucene.search.Similarity; +import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager; import java.io.IOException; -import java.io.File; /** * Implements a lucene index which is based on a @@ -45,26 +43,27 @@ private IndexListener listener; /** - * Creates a new PersistentIndex based on the file system - * indexDir. + * Creates a new PersistentIndex. + * * @param name the name of this index. - * @param indexDir the directory to store the index. * @param analyzer the analyzer for text tokenizing. * @param similarity the similarity implementation. * @param cache the document number cache * @param indexingQueue the indexing queue. + * @param directoryManager the directory manager. * @throws IOException if an error occurs while opening / creating the * index. */ - PersistentIndex(String name, File indexDir, Analyzer analyzer, + PersistentIndex(String name, Analyzer analyzer, Similarity similarity, DocNumberCache cache, - IndexingQueue indexingQueue) + IndexingQueue indexingQueue, + DirectoryManager directoryManager) throws IOException { - super(analyzer, similarity, FSDirectory.getDirectory(indexDir, new NativeFSLockFactory(indexDir)), + super(analyzer, similarity, directoryManager.getDirectory(name), cache, indexingQueue); this.name = name; if (isExisting()) { - IndexMigration.migrate(this, indexDir); + IndexMigration.migrate(this, directoryManager); } } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/RedoLog.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/RedoLog.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/RedoLog.java (working copy) @@ -18,6 +18,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.lucene.store.Directory; +import org.apache.jackrabbit.core.query.lucene.directory.IndexOutputStream; +import org.apache.jackrabbit.core.query.lucene.directory.IndexInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -26,10 +29,7 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; -import java.io.File; -import java.io.FileInputStream; import java.io.OutputStream; -import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; @@ -50,6 +50,11 @@ private static final Logger log = LoggerFactory.getLogger(RedoLog.class); /** + * Default name of the redo log file + */ + private static final String REDO_LOG = "redo.log"; + + /** * Implements a {@link ActionCollector} that counts all entries and sets * {@link #entryCount}. */ @@ -60,9 +65,9 @@ }; /** - * The log file + * The directory where the log file is stored. */ - private final File logFile; + private final Directory dir; /** * The number of log entries in the log file @@ -75,17 +80,14 @@ private Writer out; /** - * Creates a new RedoLog instance based on the file - * logFile - * @param log the redo log file. + * Creates a new RedoLog instance, which stores its log in the + * given directory. + * + * @param dir the directory where the redo log file is located. + * @throws IOException if an error occurs while reading the redo log. */ - RedoLog(File log) throws IOException { - this.logFile = log; - // create the log file if not there - if (!log.exists()) { - log.getParentFile().mkdirs(); - log.createNewFile(); - } + RedoLog(Directory dir) throws IOException { + this.dir = dir; read(ENTRY_COUNTER); } @@ -157,8 +159,7 @@ out.close(); out = null; } - // truncate file - new FileOutputStream(logFile).close(); + dir.deleteFile(REDO_LOG); entryCount = 0; } @@ -169,7 +170,7 @@ */ private void initOut() throws IOException { if (out == null) { - OutputStream os = new FileOutputStream(logFile, true); + OutputStream os = new IndexOutputStream(dir.createOutput(REDO_LOG)); out = new BufferedWriter(new OutputStreamWriter(os)); } } @@ -182,7 +183,10 @@ * log file. */ private void read(ActionCollector collector) throws IOException { - InputStream in = new FileInputStream(logFile); + if (!dir.fileExists(REDO_LOG)) { + return; + } + InputStream in = new IndexInputStream(dir.openInput(REDO_LOG)); try { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line; Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (revision 714007) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (working copy) @@ -28,6 +28,8 @@ import org.apache.jackrabbit.core.query.ExecutableQuery; import org.apache.jackrabbit.core.query.QueryHandler; import org.apache.jackrabbit.core.query.QueryHandlerContext; +import org.apache.jackrabbit.core.query.lucene.directory.DirectoryManager; +import org.apache.jackrabbit.core.query.lucene.directory.FSDirectoryManager; import org.apache.jackrabbit.core.state.NodeState; import org.apache.jackrabbit.core.state.NodeStateIterator; import org.apache.jackrabbit.core.state.ItemStateManager; @@ -405,6 +407,16 @@ private Similarity similarity = Similarity.getDefault(); /** + * The name of the directory manager class implementation. + */ + private String directoryManagerClass = FSDirectoryManager.class.getName(); + + /** + * The directory manager. + */ + private DirectoryManager directoryManager; + + /** * Indicates if this SearchIndex is closed and cannot be used * anymore. */ @@ -437,16 +449,15 @@ extractor = createTextExtractor(); synProvider = createSynonymProvider(); + directoryManager = createDirectoryManager(); - File indexDir = new File(path); - if (context.getParentHandler() instanceof SearchIndex) { // use system namespace mappings SearchIndex sysIndex = (SearchIndex) context.getParentHandler(); nsMappings = sysIndex.getNamespaceMappings(); } else { // read local namespace mappings - File mapFile = new File(indexDir, NS_MAPPING_FILE); + File mapFile = new File(new File(path), NS_MAPPING_FILE); if (mapFile.exists()) { // be backward compatible and use ns_mappings.properties from // index folder @@ -463,7 +474,7 @@ indexingConfig = createIndexingConfiguration(nsMappings); analyzer.setIndexingConfig(indexingConfig); - index = new MultiIndex(indexDir, this, excludedIDs, nsMappings); + index = new MultiIndex(this, excludedIDs); if (index.numDocs() == 0) { Path rootPath; if (excludedIDs.isEmpty()) { @@ -849,6 +860,13 @@ } /** + * @return the directory manager for this search index. + */ + public DirectoryManager getDirectoryManager() { + return directoryManager; + } + + /** * Returns an index reader for this search index. The caller of this method * is responsible for closing the index reader when he is finished using * it. @@ -1002,6 +1020,31 @@ } /** + * @return an initialized {@link DirectoryManager}. + * @throws IOException if the directory manager cannot be instantiated or + * an exception occurs while initializing the manager. + */ + protected DirectoryManager createDirectoryManager() + throws IOException { + try { + Class clazz = Class.forName(directoryManagerClass); + if (!DirectoryManager.class.isAssignableFrom(clazz)) { + throw new IOException(directoryManagerClass + + " is not a DirectoryManager implementation"); + } + DirectoryManager df = (DirectoryManager) clazz.newInstance(); + df.init(this); + return df; + } catch (IOException e) { + throw e; + } catch (Exception e) { + IOException ex = new IOException(); + ex.initCause(e); + throw ex; + } + } + + /** * Creates a file system resource to the synonym provider configuration. * * @return a file system resource or null if no path was @@ -1898,6 +1941,23 @@ return maxVolatileIndexSize; } + /** + * @return the name of the directory manager class. + */ + public String getDirectoryManagerClass() { + return directoryManagerClass; + } + + /** + * Sets name of the directory manager class. The class must implement + * {@link DirectoryManager}. + * + * @param className the name of the class that implements directory manager. + */ + public void setDirectoryManagerClass(String className) { + this.directoryManagerClass = className; + } + //----------------------------< internal >---------------------------------- /** Index: src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStreamTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStreamTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexInputStreamTest.java (revision 0) @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import java.io.IOException; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.Random; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.store.IndexOutput; + +import junit.framework.TestCase; + +/** + * IndexInputStreamTest performs tests on {@link IndexInputStream}. + */ +public class IndexInputStreamTest extends TestCase { + + public void testIndexInputStream() throws IOException { + checkStream(0, 0); + checkStream(0, 128); + checkStream(128, 0); + checkStream(128, 128); + checkStream(127, 128); + checkStream(129, 128); + checkStream(300, 128); + } + + private void checkStream(int size, int buffer) throws IOException { + Random rand = new Random(); + byte[] data = new byte[size]; + rand.nextBytes(data); + Directory dir = new RAMDirectory(); + IndexOutput out = dir.createOutput("test"); + out.writeBytes(data, data.length); + out.close(); + InputStream in = new IndexInputStream(dir.openInput("test")); + if (buffer != 0) { + in = new BufferedInputStream(in, buffer); + } + byte[] buf = new byte[3]; + int len; + int pos = 0; + while ((len = in.read(buf)) > -1) { + for (int i = 0; i < len; i++, pos++) { + assertEquals(data[pos], buf[i]); + } + } + in.close(); + // assert length + assertEquals(data.length, pos); + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\query\lucene\directory\IndexInputStreamTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStreamTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStreamTest.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/query/lucene/directory/IndexOutputStreamTest.java (revision 0) @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.BufferedOutputStream; +import java.util.Random; + +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.store.IndexInput; + +import junit.framework.TestCase; + +/** + * IndexOutputStreamTest performs tests on {@link IndexOutputStream}. + */ +public class IndexOutputStreamTest extends TestCase { + + public void testIndexOutputStream() throws IOException { + checkStream(0, 0); + checkStream(0, 128); + checkStream(128, 0); + checkStream(127, 128); + checkStream(128, 128); + checkStream(129, 128); + checkStream(300, 128); + } + + private void checkStream(int size, int buffer) throws IOException { + Random rand = new Random(); + byte[] data = new byte[size]; + rand.nextBytes(data); + Directory dir = new RAMDirectory(); + OutputStream out = new IndexOutputStream(dir.createOutput("test")); + if (buffer != 0) { + out = new BufferedOutputStream(out, buffer); + } + out.write(data); + out.close(); + + byte[] buf = new byte[3]; + int pos = 0; + IndexInput in = dir.openInput("test"); + for (;;) { + int len = (int) Math.min(buf.length, in.length() - pos); + in.readBytes(buf, 0, len); + for (int i = 0; i < len; i++, pos++) { + assertEquals(data[pos], buf[i]); + } + if (len == 0) { + // EOF + break; + } + } + in.close(); + + // assert length + assertEquals(data.length, pos); + } +} Property changes on: src\test\java\org\apache\jackrabbit\core\query\lucene\directory\IndexOutputStreamTest.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/test/java/org/apache/jackrabbit/core/query/lucene/directory/TestAll.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/query/lucene/directory/TestAll.java (revision 0) +++ src/test/java/org/apache/jackrabbit/core/query/lucene/directory/TestAll.java (revision 0) @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.core.query.lucene.directory; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Test suite that includes all testcases for the directory module. + */ +public class TestAll extends TestCase { + + /** + * Returns a Test suite that executes all tests inside this + * package. + * + * @return a Test suite that executes all tests inside this + * package. + */ + public static Test suite() { + TestSuite suite = new TestSuite("Directory tests"); + + suite.addTestSuite(IndexInputStreamTest.class); + suite.addTestSuite(IndexOutputStreamTest.class); + + return suite; + } +} \ No newline at end of file Property changes on: src\test\java\org\apache\jackrabbit\core\query\lucene\directory\TestAll.java ___________________________________________________________________ Added: svn:eol-style + native