Index: contrib/distributed/src/org/apache/lucene/distributed/ClassService.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/ClassService.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/ClassService.java	(revision 0)
@@ -0,0 +1,9 @@
+package org.apache.lucene.distributed;
+
+/**
+ * Remote service used to load class bytes from
+ */
+public interface ClassService extends CLInterface {
+  public static final long serialVersionUID = 1l;
+  
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/CLInterface.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/CLInterface.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/CLInterface.java	(revision 0)
@@ -0,0 +1,16 @@
+package org.apache.lucene.distributed;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.lucene.distributed.RMIClasses.ClassKey;
+
+/**
+ * Interface for loading multi versioned class bytes.  The ClassKey
+ * holds the class name and serialVersionUID.
+ *
+ */
+public interface CLInterface {
+  public byte[] getResource(String resource) throws IOException;
+  public byte[] loadClassData(ClassKey classKey) throws IOException;
+}
\ No newline at end of file
Index: contrib/distributed/src/org/apache/lucene/distributed/GetLuceneClasses.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/GetLuceneClasses.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/GetLuceneClasses.java	(revision 0)
@@ -0,0 +1,88 @@
+package org.apache.lucene.distributed;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * Finds Lucene core Lucene subclasses
+ *
+ */
+public class GetLuceneClasses {
+  Set<String> rootNames;
+  static Set<String> defaultRootNames;
+  static {
+    defaultRootNames = new HashSet<String>();
+    /**
+    defaultRootNames.add("org.apache.lucene.search.Query");
+    defaultRootNames.add("org.apache.lucene.search.Filter");
+    defaultRootNames.add("org.apache.lucene.analysis.Analyzer");
+    defaultRootNames.add("org.apache.lucene.document.Document");
+    defaultRootNames.add("org.apache.lucene.document.Fieldable");
+    defaultRootNames.add("org.apache.lucene.search.Similarity");
+    defaultRootNames.add("org.apache.lucene.search.Weight");
+    **/
+    defaultRootNames.add("java.lang.Object");
+  }
+
+  public static void main(String[] args) throws Exception {
+    // GetLuceneClasses getLuceneClasses = new
+    // GetLuceneClasses(defaultRootNames);
+    // System.out.println(getLuceneClasses.get() + "");
+    GenerateLuceneClassExclude e = new GenerateLuceneClassExclude(new File(
+        "G:\\oceangoogle\\trunk\\distributedlucene\\src\\org\\apache\\lucene\\distributed\\LuceneClasses.java"));
+    e.generate();
+    System.out.println("finished");
+  }
+
+  public static class GenerateLuceneClassExclude {
+    File file;
+
+    public GenerateLuceneClassExclude(File file) {
+      this.file = file;
+    }
+
+    public void generate() throws Exception {
+      StringBuilder b = new StringBuilder();
+      b.append("package org.apache.lucene.distributed;\n\n");
+      b.append("import java.util.HashSet;\n");
+      b.append("import java.util.Set;\n\n");
+      b.append("public class LuceneClasses {\n");
+      b.append("  public static Set<String> classes = new HashSet<String>();\n\n");
+      b.append("  static {\n");
+      GetLuceneClasses glc = new GetLuceneClasses(defaultRootNames);
+      Set<String> set = glc.get();
+      for (String name : set) {
+        String s = name.substring(name.lastIndexOf('.')+1, name.length());
+        //System.out.println(s);
+        if (s.startsWith("Test")) continue;
+        b.append("    classes.add(\"" + name + "\");\n");
+      }
+      b.append("  }");
+      b.append("}");
+
+      FileUtils.writeStringToFile(file, b.toString());
+    }
+  }
+
+  public GetLuceneClasses(Set<String> rootNames) {
+    this.rootNames = rootNames;
+  }
+
+  public Set<String> get() throws Exception {
+    Set<String> names = new HashSet<String>();
+    ResolverUtil resolverUtil = new ResolverUtil();
+    for (String rootName : rootNames) {
+      Class cl = Class.forName(rootName);
+      resolverUtil.findImplementations(cl, "org.apache.lucene");
+    }
+    Set<Class> classes = resolverUtil.getClasses();
+    for (Class c : classes) {
+      names.add(c.getName());
+    }
+    return names;
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/IndexManagerService.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/IndexManagerService.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/IndexManagerService.java	(revision 0)
@@ -0,0 +1,33 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.Serializable;
+
+import org.apache.lucene.analysis.Analyzer;
+
+public interface IndexManagerService {
+  
+  public static class IndexInfo implements Serializable {
+    public static final long serialVersionUID = 1l;
+    public String name;
+    public String serviceName;
+    public long length;
+    public IndexSettings indexSettings;
+  }
+  
+  public static class IndexSettings implements Serializable {
+    public static final long serialVersionUID = 1l;
+    public Analyzer defaultAnalyzer;
+    public int maxFieldLength;
+    public Double ramBufferSizeMB;
+  }
+  
+  /**
+   * Creates index of name, returns the name in the NameService
+   * @param name
+   * @return
+   * @throws Exception
+   */
+  public IndexService createIndex(String name, IndexSettings indexSettings) throws Exception;
+  public IndexInfo[] getIndexInfos() throws Exception;
+  public void deleteIndex(String name) throws Exception;
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/IndexService.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/IndexService.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/IndexService.java	(revision 0)
@@ -0,0 +1,55 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.Serializable;
+import java.rmi.Remote;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.distributed.index.IndexManagerService.IndexInfo;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+
+public interface IndexService extends Remote {
+  public static class IndexVersion implements Serializable {
+    public static final long serialVersionUID = 1l;
+    public long generation;
+  }
+  
+  public static interface Operation {
+  }
+  
+  public static class Add implements Serializable, Operation {
+    public static final long serialVersionUID = 1l;
+    public Analyzer analyzer;
+    public Document document;
+  }
+  
+  public static class Update implements Serializable, Operation {
+    public static final long serialVersionUID = 1l;
+    public Document document;
+    public Term term;
+    public Analyzer analyzer;
+  }
+  
+  public static class Delete implements Serializable, Operation {
+    public static final long serialVersionUID = 1l;
+    public Query query;
+    public Term term;
+  }
+  
+  public SearchableService reopen() throws Exception;
+  public void close() throws Exception;
+  public IndexInfo getIndexInfo() throws Exception;
+  
+  /**
+   * Executes batch of index changing operations (add, update, or delete) 
+   * @param operations
+   * @throws Exception
+   */
+  public void execute(Operation[] operations) throws Exception;
+  public void addDocument(Document document, Analyzer analyzer) throws Exception;
+  public void updateDocument(Term term, Document document, Analyzer analyzer) throws Exception;
+  public void deleteDocuments(Term term) throws Exception;
+  public void deleteDocuments(Query query) throws Exception;
+  public void flush() throws Exception;
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/IndexServiceImpl.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/IndexServiceImpl.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/IndexServiceImpl.java	(revision 0)
@@ -0,0 +1,204 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.IOException;
+import java.util.LinkedList;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.distributed.RMI;
+import org.apache.lucene.distributed.RMI.Closeable;
+import org.apache.lucene.distributed.index.IndexManagerService.IndexInfo;
+import org.apache.lucene.distributed.index.IndexManagerService.IndexSettings;
+import org.apache.lucene.distributed.index.IndexService.Add;
+import org.apache.lucene.distributed.index.IndexService.Delete;
+import org.apache.lucene.distributed.index.IndexService.IndexVersion;
+import org.apache.lucene.distributed.index.IndexService.Operation;
+import org.apache.lucene.distributed.index.IndexService.Update;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexCommit;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.HitCollector;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TopFieldDocs;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+
+public class IndexServiceImpl implements IndexService {
+  private LinkedList<SearchableServiceImpl> searchables = new LinkedList<SearchableServiceImpl>();
+  private IndexWriter indexWriter;
+  private Directory directory;
+  private RMI.Server rmiServer;
+  private String name;
+  private String serviceName;
+
+  public IndexServiceImpl(String name, String serviceName, Directory directory, IndexSettings indexSettings, RMI.Server rmiServer) throws IOException {
+    this.name = name;
+    this.serviceName = serviceName;
+    this.directory = directory;
+    this.rmiServer = rmiServer;
+    FSDirectory fsDirectory = (FSDirectory) directory;
+    IndexWriter.unlock(directory);
+    boolean create = !IndexReader.indexExists(directory);
+    indexWriter = new IndexWriter(directory, indexSettings.defaultAnalyzer, create, new IndexWriter.MaxFieldLength(indexSettings.maxFieldLength));
+    if (indexSettings.ramBufferSizeMB != null) {
+      indexWriter.setRAMBufferSizeMB(indexSettings.ramBufferSizeMB.doubleValue());
+    }
+  }
+
+  public class SearchableServiceImpl implements SearchableService, Closeable {
+    IndexReader reader;
+    IndexSearcher searcher;
+    String serviceName;
+
+    public SearchableServiceImpl(String serviceName, IndexReader reader) {
+      this.serviceName = serviceName;
+      this.reader = reader;
+      searcher = new IndexSearcher(reader);
+    }
+    
+    public IndexVersion getIndexVersion() throws Exception {
+      IndexCommit indexCommit = reader.getIndexCommit();
+      IndexVersion indexVersion = new IndexVersion();
+      indexVersion.generation = indexCommit.getGeneration();
+      return indexVersion;
+    }
+    
+    public void search(Weight weight, Filter filter, HitCollector results) throws IOException {
+      throw new UnsupportedOperationException("");
+    }
+
+    public void close() throws IOException {
+      searcher.close();
+      reader.close();
+    }
+
+    public int docFreq(Term term) throws IOException {
+      return searcher.docFreq(term);
+    }
+
+    public int[] docFreqs(Term[] terms) throws IOException {
+      return searcher.docFreqs(terms);
+    }
+
+    public int maxDoc() throws IOException {
+      return searcher.maxDoc();
+    }
+
+    public TopDocs search(Weight weight, Filter filter, int n) throws IOException {
+      return searcher.search(weight, filter, n);
+    }
+
+    public Document doc(int i) throws CorruptIndexException, IOException {
+      return searcher.doc(i);
+    }
+    
+    public Document[] docs(int[] docs, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
+      Document[] documents = new Document[docs.length];
+      for (int x=0; x < docs.length; x++) {
+        documents[x] = searcher.doc(docs[x], fieldSelector);
+      }
+      return documents;
+    }
+    
+    public Document doc(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
+      return searcher.doc(n, fieldSelector);
+    }
+
+    public Query rewrite(Query query) throws IOException {
+      return searcher.rewrite(query);
+    }
+
+    public Explanation explain(Weight weight, int doc) throws IOException {
+      return searcher.explain(weight, doc);
+    }
+
+    public TopFieldDocs search(Weight weight, Filter filter, int n, Sort sort) throws IOException {
+      return searcher.search(weight, filter, n, sort);
+    }
+  }
+
+  public synchronized SearchableService reopen() throws Exception {
+    SearchableServiceImpl currentSearchable = searchables.peek();
+    if (currentSearchable == null) {
+      IndexReader reader = IndexReader.open(directory);
+      currentSearchable = addSearchable(reader);
+    } else {
+      IndexReader newReader = currentSearchable.reader.reopen();
+      if (newReader != currentSearchable.reader) {
+        currentSearchable = addSearchable(newReader);
+      }
+    }
+    return currentSearchable;
+  }
+  
+  private SearchableServiceImpl addSearchable(IndexReader reader) throws IOException {
+    long generation = reader.getIndexCommit().getGeneration();
+    String serviceName = "index."+name+".searchable."+generation;
+    SearchableServiceImpl currentSearchable = new SearchableServiceImpl(serviceName, reader);
+    rmiServer.addService(serviceName, currentSearchable, true);
+    searchables.clear();
+    searchables.addFirst(currentSearchable);
+    return currentSearchable;
+  }
+  
+  public void flush() throws Exception {
+    indexWriter.commit();
+  }
+  
+  public synchronized void close() throws Exception {
+    for (SearchableServiceImpl searchable : searchables) {
+      searchable.close();
+    }
+  }
+
+  public IndexInfo getIndexInfo() throws Exception {
+    IndexInfo indexInfo = new IndexInfo();
+    indexInfo.name = name;
+    
+    return indexInfo;
+  }
+  
+  // TODO: needs to return the ops that worked, and ones that failed
+  public void execute(Operation[] operations) throws Exception {
+    for (Operation operation : operations) {
+      if (operation instanceof Add) {
+        Add add = (Add)operation;
+        if (add.analyzer == null) indexWriter.addDocument(add.document);
+        else indexWriter.addDocument(add.document, add.analyzer);
+      } else if (operation instanceof Update) {
+        Update update = (Update)operation;
+        if (update.analyzer == null) indexWriter.updateDocument(update.term, update.document);
+        else indexWriter.updateDocument(update.term, update.document, update.analyzer);
+      } else if (operation instanceof Delete) {
+        Delete delete = (Delete)operation;
+        if (delete.query != null) indexWriter.deleteDocuments(delete.query);
+        else if (delete.term != null) indexWriter.deleteDocuments(delete.term);
+      }
+    }
+  }
+  
+  public void addDocument(Document document, Analyzer analyzer) throws Exception {
+    indexWriter.addDocument(document, analyzer);
+  }
+
+  public void updateDocument(Term term, Document document, Analyzer analyzer) throws Exception {
+    indexWriter.updateDocument(term, document, analyzer);
+  }
+
+  public void deleteDocuments(Term term) throws Exception {
+    indexWriter.deleteDocuments(term);
+  }
+  
+  public void deleteDocuments(Query query) throws Exception {
+    indexWriter.deleteDocuments(query);
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/LuceneClient.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/LuceneClient.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/LuceneClient.java	(revision 0)
@@ -0,0 +1,18 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import org.apache.lucene.distributed.RMI;
+
+public class LuceneClient {
+  public final RMI rmi;
+  public final IndexManagerService indexManagerService;
+  
+  public LuceneClient(InetSocketAddress addr, RMI rmi) throws IOException {
+    this.rmi = rmi;
+    indexManagerService = (IndexManagerService)rmi.getProxy("indexManagerService", IndexManagerService.class, 1l, addr);
+  }
+  
+  
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/LuceneServer.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/LuceneServer.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/LuceneServer.java	(revision 0)
@@ -0,0 +1,77 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.distributed.RMI;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+
+public class LuceneServer {
+  RMI rmi;
+  File dir;
+  Map<String,IndexServiceImpl> indexes = new HashMap<String,IndexServiceImpl>();
+  IndexManagerServiceImpl indexManagerServiceImpl;
+
+  public LuceneServer(RMI rmi, File dir) throws Exception {
+    this.rmi = rmi;
+    this.dir = dir;
+    indexManagerServiceImpl = new IndexManagerServiceImpl();
+    rmi.getServer().addService("indexManagerService", indexManagerServiceImpl, false);
+    for (File file : dir.listFiles()) {
+      String name = file.getName();
+      if (file.isDirectory() && name.startsWith("index.")) {
+        String indexName = name.substring(name.indexOf('.'), name.length());
+        indexManagerServiceImpl.createIndex(indexName, file, null);
+      }
+    }
+  }
+
+  public class IndexManagerServiceImpl implements IndexManagerService {
+    public IndexService createIndex(String name, IndexSettings indexSettings) throws Exception {
+      File indexDir = new File(dir, name);
+      if (!indexDir.exists())
+        indexDir.mkdirs();
+      return createIndex(name, indexDir, indexSettings);
+    }
+    
+    private IndexService createIndex(String name, File dir, IndexSettings indexSettings) throws Exception {
+      RMI.Server rmiServer = rmi.getServer();
+      File indexSettingsFile = new File(dir, "indexsettings.obj");
+      if (indexSettings != null) {
+        if (!indexSettingsFile.exists()) {
+          // save the classes that are special to the serialized object
+          FileOutputStream fileOut = new FileOutputStream(indexSettingsFile);
+          ObjectOutputStream objOut = rmiServer.getRMIClasses().createOutput(fileOut, rmiServer, true);
+          objOut.writeObject(indexSettings);
+          objOut.close();
+        }
+      } else {
+        if (indexSettingsFile.exists()) {
+          // load special classes from the serialized object
+          ObjectInputStream objIn = rmiServer.getRMIClasses().createInput(new FileInputStream(indexSettingsFile), rmi, true);
+          indexSettings = (IndexSettings) objIn.readObject();
+        }
+      }
+      Directory directory = FSDirectory.getDirectory(dir);
+      String serviceName = "index." + name;
+      IndexServiceImpl indexServiceImpl = new IndexServiceImpl(name, serviceName, directory, indexSettings, rmi.getServer());
+      indexes.put(name, indexServiceImpl);
+      rmiServer.addService(serviceName, indexServiceImpl, false);
+      return indexServiceImpl;
+    }
+
+    public IndexInfo[] getIndexInfos() throws Exception {
+      return null;
+    }
+
+    public void deleteIndex(String name) throws Exception {
+
+    }
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/index/SearchableService.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/index/SearchableService.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/index/SearchableService.java	(revision 0)
@@ -0,0 +1,14 @@
+package org.apache.lucene.distributed.index;
+
+import java.io.IOException;
+
+import org.apache.lucene.distributed.index.IndexService.IndexVersion;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.FieldSelector;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.search.Searchable;
+
+public interface SearchableService extends Searchable {
+  public IndexVersion getIndexVersion() throws Exception;
+  public Document[] docs(int[] docs, FieldSelector fieldSelector) throws CorruptIndexException, IOException;
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/LuceneClasses.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/LuceneClasses.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/LuceneClasses.java	(revision 0)
@@ -0,0 +1,792 @@
+package org.apache.lucene.distributed;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class LuceneClasses {
+  public static Set<String> classes = new HashSet<String>();
+
+  static {
+    classes.add("org.apache.lucene.ocean.util.Timeout$TimeoutException");
+    classes.add("org.apache.lucene.ocean.CommitResult");
+    classes.add("org.apache.lucene.index.FieldInfos");
+    classes.add("org.apache.lucene.search.spans.SpanNearQuery");
+    classes.add("org.apache.lucene.search.MultiPhraseQuery$MultiPhraseWeight");
+    classes.add("org.apache.lucene.ocean.Deletes$DeleteByQuery");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$CreationPlaceholder");
+    classes.add("org.apache.lucene.search.FilteredQuery");
+    classes.add("org.apache.lucene.search.TermScorer");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$Cache");
+    classes.add("org.apache.lucene.index.SegmentMergeInfo");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$LogFailure");
+    classes.add("org.apache.lucene.search.SortComparatorSource");
+    classes.add("org.apache.lucene.analysis.Token");
+    classes.add("org.apache.lucene.document.FieldSelector");
+    classes.add("org.apache.lucene.search.function.CustomScoreQuery");
+    classes.add("org.apache.lucene.ocean.util.ByteArrayIndexOutput");
+    classes.add("org.apache.lucene.ocean.LogDirectory");
+    classes.add("org.apache.lucene.store.ChecksumIndexInput");
+    classes.add("org.apache.lucene.ocean.util.SortedList$SortedListIterator");
+    classes.add("org.apache.lucene.search.spans.NearSpansUnordered");
+    classes.add("org.apache.lucene.index.DocHelper");
+    classes.add("org.apache.lucene.analysis.CharArraySet");
+    classes.add("org.apache.lucene.search.FieldCache");
+    classes.add("org.apache.lucene.index.ByteSliceWriter");
+    classes.add("org.apache.lucene.index.SnapshotDeletionPolicy");
+    classes.add("org.apache.lucene.store.SimpleFSLock");
+    classes.add("org.apache.lucene.index.IndexCommit");
+    classes.add("org.apache.lucene.search.function.FieldScoreQuery$Type");
+    classes.add("org.apache.lucene.search.PrefixGenerator");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$4");
+    classes.add("org.apache.lucene.ocean.TransactionSystem$MaybeMergesTimer");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$10");
+    classes.add("org.apache.lucene.search.QueryWrapperFilter");
+    classes.add("org.apache.lucene.search.Searcher");
+    classes.add("org.apache.lucene.search.ReqExclScorer");
+    classes.add("org.apache.lucene.search.FieldDoc");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$Update");
+    classes.add("org.apache.lucene.search.spans.SpanWeight");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl$1");
+    classes.add("org.apache.lucene.distributed.index.IndexManagerService$IndexInfo");
+    classes.add("org.apache.lucene.ocean.database.OceanObject");
+    classes.add("org.apache.lucene.ocean.Documents");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$9");
+    classes.add("org.apache.lucene.index.RepeatingTokenStream");
+    classes.add("org.apache.lucene.search.payloads.BoostingTermQuery");
+    classes.add("org.apache.lucene.ocean.log.LogFile");
+    classes.add("org.apache.lucene.ocean.util.Timeout$Listener");
+    classes.add("org.apache.lucene.util.BitVector");
+    classes.add("org.apache.lucene.search.function.ReverseOrdFieldSource$1");
+    classes.add("org.apache.lucene.store.RAMOutputStream");
+    classes.add("org.apache.lucene.util._TestUtil");
+    classes.add("org.apache.lucene.queryParser.TokenMgrError");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$MemoryIndexReader$1");
+    classes.add("org.apache.lucene.index.MultiLevelSkipListReader$SkipBuffer");
+    classes.add("org.apache.lucene.search.function.ValueSourceQuery$ValueSourceScorer");
+    classes.add("org.apache.lucene.util.UnicodeUtil$UTF16Result");
+    classes.add("org.apache.lucene.search.SampleComparable$1$1");
+    classes.add("org.apache.lucene.search.spans.TermSpans");
+    classes.add("org.apache.lucene.ocean.SingleThreadTransaction");
+    classes.add("org.apache.lucene.index.TermInfosWriter");
+    classes.add("org.apache.lucene.search.PrefixQuery");
+    classes.add("org.apache.lucene.ocean.snapshotlog.SnapshotLogManager");
+    classes.add("org.apache.lucene.index.SerialMergeScheduler");
+    classes.add("org.apache.lucene.ocean.util.VDataInputStream");
+    classes.add("org.apache.lucene.search.ParallelMultiSearcher");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$ResourceTest");
+    classes.add("org.apache.lucene.ocean.util.Timeout$TimeoutRuntimeException");
+    classes.add("org.apache.lucene.store.NativeFSLockFactory");
+    classes.add("org.apache.lucene.ThreadSafetyTest");
+    classes.add("org.apache.lucene.search.BooleanScorer2$Coordinator");
+    classes.add("org.apache.lucene.search.QueryWrapperFilter$1");
+    classes.add("org.apache.lucene.distributed.RMIClasses$RMIObjectInputStream$1");
+    classes.add("org.apache.lucene.ocean.util.Bytes$ByteArrayOutputStream");
+    classes.add("org.apache.lucene.search.DisjunctionMaxQuery$DisjunctionMaxWeight");
+    classes.add("org.apache.lucene.store.VerifyingLockFactory");
+    classes.add("org.apache.lucene.analysis.LowerCaseFilter");
+    classes.add("org.apache.lucene.ocean.Indexes");
+    classes.add("org.apache.lucene.analysis.standard.StandardAnalyzer");
+    classes.add("org.apache.lucene.index.Payload");
+    classes.add("org.apache.lucene.store.MMapDirectory$MultiMMapIndexInput");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermDocumentInformation$3");
+    classes.add("org.apache.lucene.analysis.Analyzer");
+    classes.add("org.apache.lucene.search.ConstantScoreQuery$ConstantScorer");
+    classes.add("org.apache.lucene.AnalysisTest");
+    classes.add("org.apache.lucene.search.IndexSearcher");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$Context");
+    classes.add("org.apache.lucene.search.TermQuery$TermWeight");
+    classes.add("org.apache.lucene.distributed.index.IndexService$Operation");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$Result");
+    classes.add("org.apache.lucene.search.MatchAllDocsQuery");
+    classes.add("org.apache.lucene.index.BufferedNorms");
+    classes.add("org.apache.lucene.ocean.MultiThreadTransaction");
+    classes.add("org.apache.lucene.distributed.ResolverUtil");
+    classes.add("org.apache.lucene.index.CompoundFileWriter$FileEntry");
+    classes.add("org.apache.lucene.search.SpanFilterResult$StartEnd");
+    classes.add("org.apache.lucene.index.FieldSortedTermVectorMapper");
+    classes.add("org.apache.lucene.analysis.TokenFilter");
+    classes.add("org.apache.lucene.search.TimeLimitedCollector");
+    classes.add("org.apache.lucene.util.English");
+    classes.add("org.apache.lucene.search.HitDoc");
+    classes.add("org.apache.lucene.search.FieldCache$ShortParser");
+    classes.add("org.apache.lucene.search.DefaultSimilarity");
+    classes.add("org.apache.lucene.search.BooleanScorer$Bucket");
+    classes.add("org.apache.lucene.search.function.OrdFieldSource");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$Action");
+    classes.add("org.apache.lucene.index.CheckIndex$MySegmentTermDocs");
+    classes.add("org.apache.lucene.ocean.util.VDataOutputStream");
+    classes.add("org.apache.lucene.util.cache.SimpleMapCache$SynchronizedSimpleMapCache");
+    classes.add("org.apache.lucene.search.RemoteSearchable");
+    classes.add("org.apache.lucene.queryParser.QueryParser");
+    classes.add("org.apache.lucene.distributed.index.LuceneClient");
+    classes.add("org.apache.lucene.search.BooleanScorer2$1");
+    classes.add("org.apache.lucene.util.cache.Cache$SynchronizedCache");
+    classes.add("org.apache.lucene.index.LogMergePolicy");
+    classes.add("org.apache.lucene.search.HitIterator");
+    classes.add("org.apache.lucene.ocean.util.SortedList");
+    classes.add("org.apache.lucene.search.ParallelMultiSearcher$1");
+    classes.add("org.apache.lucene.ocean.util.LongSequence");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTerm$2");
+    classes.add("org.apache.lucene.ocean.log.LogFileManager$LogFileSizeCheck");
+    classes.add("org.apache.lucene.search.Similarity");
+    classes.add("org.apache.lucene.analysis.StopAnalyzer");
+    classes.add("org.apache.lucene.search.TopDocCollector");
+    classes.add("org.apache.lucene.ocean.Index$IndexSnapshotSearcher");
+    classes.add("org.apache.lucene.util.OpenBitSetDISI");
+    classes.add("org.apache.lucene.search.FieldCache$IntParser");
+    classes.add("org.apache.lucene.ocean.util.BytesPool");
+    classes.add("org.apache.lucene.util.OpenBitSet");
+    classes.add("org.apache.lucene.index.MergePolicy$MergeAbortedException");
+    classes.add("org.apache.lucene.index.IndexReader");
+    classes.add("org.apache.lucene.search.spans.SpanOrQuery$SpanQueue");
+    classes.add("org.apache.lucene.distributed.index.IndexService");
+    classes.add("org.apache.lucene.distributed.RMI$DefaultClassAccept");
+    classes.add("org.apache.lucene.document.Document$1");
+    classes.add("org.apache.lucene.index.AbortException");
+    classes.add("org.apache.lucene.util.cache.Cache");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$AddRamIndexDocumentsTask");
+    classes.add("org.apache.lucene.index.IndexWriter$MaxFieldLength");
+    classes.add("org.apache.lucene.store.LockStressTest");
+    classes.add("org.apache.lucene.index.SegmentTermPositionVector");
+    classes.add("org.apache.lucene.ocean.TransactionSystem$MaybeMergeIndexes");
+    classes.add("org.apache.lucene.distributed.RMIClasses$ClassAccept");
+    classes.add("org.apache.lucene.ocean.OceanInstantiatedIndexReader");
+    classes.add("org.apache.lucene.search.FieldDocSortedHitQueue");
+    classes.add("org.apache.lucene.document.AbstractField");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$2");
+    classes.add("org.apache.lucene.util.SortedVIntList$1");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest$1");
+    classes.add("org.apache.lucene.util.ScorerDocQueue$HeapedScorerDoc");
+    classes.add("org.apache.lucene.ocean.util.SortedList$KeySet");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermDocumentInformation$2");
+    classes.add("org.apache.lucene.search.FilterManager$FilterCleaner");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$LoadRecordHeaders");
+    classes.add("org.apache.lucene.index.DocumentsWriter");
+    classes.add("org.apache.lucene.distributed.RMI$Closeable");
+    classes.add("org.apache.lucene.index.IndexFileNames");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$StreamRecord");
+    classes.add("org.apache.lucene.search.CachingSpanFilter");
+    classes.add("org.apache.lucene.ocean.SnapshotInfo");
+    classes.add("org.apache.lucene.ocean.log.TransactionLog$SlaveBatchIterator");
+    classes.add("org.apache.lucene.distributed.ClassService");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexReader$NormUpdate");
+    classes.add("org.apache.lucene.index.TermVectorsReader");
+    classes.add("org.apache.lucene.ocean.Snapshot");
+    classes.add("org.apache.lucene.index.TermBuffer");
+    classes.add("org.apache.lucene.index.SegmentInfos$1");
+    classes.add("org.apache.lucene.index.SegmentMerger$CheckAbort");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput");
+    classes.add("org.apache.lucene.store.FSDirectory$FSIndexInput$Descriptor");
+    classes.add("org.apache.lucene.analysis.BuffTokenFilter");
+    classes.add("org.apache.lucene.search.spans.SpanFirstQuery");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$Insert");
+    classes.add("org.apache.lucene.index.SegmentReader$Norm");
+    classes.add("org.apache.lucene.StoreTest");
+    classes.add("org.apache.lucene.ocean.util.SortedList$ValueIterator");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$MutableInteger");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexWriter");
+    classes.add("org.apache.lucene.search.spans.SpanFirstQuery$1");
+    classes.add("org.apache.lucene.search.Searchable");
+    classes.add("org.apache.lucene.distributed.index.IndexManagerService");
+    classes.add("org.apache.lucene.index.MultipleTermPositions$TermPositionsQueue");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$2");
+    classes.add("org.apache.lucene.ocean.Index$IndexNeverCompletedCopyException");
+    classes.add("org.apache.lucene.index.DefaultSkipListReader");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex");
+    classes.add("org.apache.lucene.ocean.DiskIndex");
+    classes.add("org.apache.lucene.ocean.WriteableMemoryIndex");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$6");
+    classes.add("org.apache.lucene.index.CheckIndex");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$6");
+    classes.add("org.apache.lucene.search.Sort");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest");
+    classes.add("org.apache.lucene.store.LockVerifyServer");
+    classes.add("org.apache.lucene.ThreadSafetyTest$SearcherThread");
+    classes.add("org.apache.lucene.index.TermVectorEntry");
+    classes.add("org.apache.lucene.search.ScoreDocComparator$2");
+    classes.add("org.apache.lucene.analysis.StopAnalyzer$SavedStreams");
+    classes.add("org.apache.lucene.ocean.util.Timeout$TimerThread");
+    classes.add("org.apache.lucene.util.StringHelper");
+    classes.add("org.apache.lucene.search.FilteredQuery$1$1");
+    classes.add("org.apache.lucene.store.ClassicFile$1");
+    classes.add("org.apache.lucene.ocean.DiskIndex$DiskIndexSnapshot");
+    classes.add("org.apache.lucene.index.SortedTermVectorMapper");
+    classes.add("org.apache.lucene.search.WildcardTermEnum");
+    classes.add("org.apache.lucene.search.CachingWrapperFilterHelper");
+    classes.add("org.apache.lucene.store.FSDirectory$FSIndexInput");
+    classes.add("org.apache.lucene.distributed.index.LuceneServer$IndexManagerServiceImpl");
+    classes.add("org.apache.lucene.index.SnapshotDeletionPolicy$MyCommitPoint");
+    classes.add("org.apache.lucene.search.FieldCache$FloatParser");
+    classes.add("org.apache.lucene.ocean.OceanConsole");
+    classes.add("org.apache.lucene.index.ConcurrentMergeScheduler$MergeThread");
+    classes.add("org.apache.lucene.ocean.TransactionSystem");
+    classes.add("org.apache.lucene.search.FieldCache$StringIndex");
+    classes.add("org.apache.lucene.index.SegmentReader$TermVectorsReaderLocal");
+    classes.add("org.apache.lucene.index.TermInfosReader$ThreadResources");
+    classes.add("org.apache.lucene.search.MatchAllDocsQuery$MatchAllDocsWeight");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$3");
+    classes.add("org.apache.lucene.analysis.SimpleAnalyzer");
+    classes.add("org.apache.lucene.distributed.RMIClasses$RMIObjectOutputStream");
+    classes.add("org.apache.lucene.util.SortedVIntList");
+    classes.add("org.apache.lucene.search.SortComparator$1");
+    classes.add("org.apache.lucene.distributed.LuceneClasses");
+    classes.add("org.apache.lucene.index.SegmentTermEnum");
+    classes.add("org.apache.lucene.search.payloads.BoostingTermQuery$BoostingTermWeight$BoostingSpanScorer");
+    classes.add("org.apache.lucene.document.MapFieldSelector");
+    classes.add("org.apache.lucene.ocean.SnapshotInfo$IndexInfo");
+    classes.add("org.apache.lucene.search.MatchAllDocsQuery$MatchAllScorer");
+    classes.add("org.apache.lucene.search.SortComparator");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$Failure");
+    classes.add("org.apache.lucene.store.ChannelTransfer$1");
+    classes.add("org.apache.lucene.analysis.WhitespaceAnalyzer");
+    classes.add("org.apache.lucene.ocean.snapshotlog.SnapshotLogFile$InfoHeader");
+    classes.add("org.apache.lucene.index.SegmentTermVector");
+    classes.add("org.apache.lucene.ocean.util.OceanRandomAccessFile");
+    classes.add("org.apache.lucene.index.FilterIndexReader");
+    classes.add("org.apache.lucene.distributed.GetLuceneClasses");
+    classes.add("org.apache.lucene.search.CheckHits");
+    classes.add("org.apache.lucene.index.memory.PatternAnalyzer$FastStringReader");
+    classes.add("org.apache.lucene.index.ParallelReader$ParallelTermEnum");
+    classes.add("org.apache.lucene.index.CompoundFileReader$CSIndexInput");
+    classes.add("org.apache.lucene.search.OceanMultiThreadSearcher$HitCollectorThread$1");
+    classes.add("org.apache.lucene.search.function.ShortFieldSource");
+    classes.add("org.apache.lucene.search.MultiThreadTermVectorsReader");
+    classes.add("org.apache.lucene.util.OpenBitSetIterator");
+    classes.add("org.apache.lucene.search.SloppyPhraseScorer");
+    classes.add("org.apache.lucene.store.MyFile$MyReader");
+    classes.add("org.apache.lucene.distributed.index.IndexManagerService$IndexSettings");
+    classes.add("org.apache.lucene.search.FilterManager$FilterCleaner$1");
+    classes.add("org.apache.lucene.ocean.database.OceanObject$OceanField");
+    classes.add("org.apache.lucene.index.StaleReaderException");
+    classes.add("org.apache.lucene.index.CharBlockPool");
+    classes.add("org.apache.lucene.LucenePackage");
+    classes.add("org.apache.lucene.search.RangeFilter");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamOutput$FieldIndex");
+    classes.add("org.apache.lucene.store.Lock$With");
+    classes.add("org.apache.lucene.store.LockFactory");
+    classes.add("org.apache.lucene.index.IndexFileNameFilter");
+    classes.add("org.apache.lucene.search.BooleanQuery");
+    classes.add("org.apache.lucene.document.Field");
+    classes.add("org.apache.lucene.queryParser.ParseException");
+    classes.add("org.apache.lucene.ocean.util.SortedList$EntrySet");
+    classes.add("org.apache.lucene.search.PrefixFilter$1");
+    classes.add("org.apache.lucene.store.SingleInstanceLockFactory");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$TimeoutFailure");
+    classes.add("org.apache.lucene.ocean.FSLogDirectory");
+    classes.add("org.apache.lucene.ocean.RamIndex");
+    classes.add("org.apache.lucene.ocean.SingleThreadSearcherPolicy");
+    classes.add("org.apache.lucene.ocean.WriteableMemoryIndex$IndexSnapshotMultiSearcher");
+    classes.add("org.apache.lucene.index.ParallelReader$ParallelTermPositions");
+    classes.add("org.apache.lucene.index.SegmentMerger");
+    classes.add("org.apache.lucene.search.ConstantScoreQuery$ConstantWeight");
+    classes.add("org.apache.lucene.index.DocumentsWriterFieldData");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$5$2");
+    classes.add("org.apache.lucene.store.LockObtainFailedException");
+    classes.add("org.apache.lucene.store.BufferedIndexOutput");
+    classes.add("org.apache.lucene.search.FilterManager");
+    classes.add("org.apache.lucene.ocean.util.BytesPool$ByteArrays");
+    classes.add("org.apache.lucene.search.BooleanClause$Occur");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$FileStreamRecord");
+    classes.add("org.apache.lucene.search.HitQueue");
+    classes.add("org.apache.lucene.search.SampleComparable");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$1$1");
+    classes.add("org.apache.lucene.search.ConstantScoreRangeQuery");
+    classes.add("org.apache.lucene.analysis.TokenStream");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$VM");
+    classes.add("org.apache.lucene.search.TopFieldDocCollector");
+    classes.add("org.apache.lucene.ocean.util.Constants");
+    classes.add("org.apache.lucene.index.SegmentInfos");
+    classes.add("org.apache.lucene.ocean.log.TransactionLog");
+    classes.add("org.apache.lucene.search.Hit");
+    classes.add("org.apache.lucene.util.UnicodeUtil$UTF8Result");
+    classes.add("org.apache.lucene.index.DirectoryIndexReader$2");
+    classes.add("org.apache.lucene.util.LuceneTestCase");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$MemoryIndexReader$2");
+    classes.add("org.apache.lucene.ocean.Batch$SlaveBatch");
+    classes.add("org.apache.lucene.analysis.standard.StandardTokenizer");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTerm$1");
+    classes.add("org.apache.lucene.search.QueryWrapperFilter$2");
+    classes.add("org.apache.lucene.util.cache.SimpleLRUCache");
+    classes.add("org.apache.lucene.util.PriorityQueue");
+    classes.add("org.apache.lucene.search.NonMatchingScorer");
+    classes.add("org.apache.lucene.ocean.log.LogFile$RecordIterator");
+    classes.add("org.apache.lucene.analysis.PayloadSetter");
+    classes.add("org.apache.lucene.SearchTest");
+    classes.add("org.apache.lucene.util.Constants");
+    classes.add("org.apache.lucene.index.MultiLevelSkipListWriter");
+    classes.add("org.apache.lucene.ocean.MemoryIndexThreadLocal");
+    classes.add("org.apache.lucene.search.function.FloatFieldSource$1");
+    classes.add("org.apache.lucene.store.SingleInstanceLock");
+    classes.add("org.apache.lucene.search.payloads.BoostingTermQuery$BoostingTermWeight");
+    classes.add("org.apache.lucene.store.MockRAMDirectory");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$7");
+    classes.add("org.apache.lucene.ocean.Index$IndexException");
+    classes.add("org.apache.lucene.document.Fieldable");
+    classes.add("org.apache.lucene.search.PhraseScorer");
+    classes.add("org.apache.lucene.distributed.index.IndexServiceImpl$SearchableServiceImpl");
+    classes.add("org.apache.lucene.queryParser.QueryParser$LookaheadSuccess");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexWriter$TermDocumentInformationFactory");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest$ModuloTokenFilter");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$Delete");
+    classes.add("org.apache.lucene.index.MergeScheduler");
+    classes.add("org.apache.lucene.queryParser.Token");
+    classes.add("org.apache.lucene.analysis.PorterStemmer");
+    classes.add("org.apache.lucene.index.MultiSegmentReader$MultiTermEnum");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$3");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest$2");
+    classes.add("org.apache.lucene.index.SegmentTermDocs");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$StreamData");
+    classes.add("org.apache.lucene.ocean.util.ByteArrayIndexInput");
+    classes.add("org.apache.lucene.index.IndexReader$1");
+    classes.add("org.apache.lucene.search.function.FloatFieldSource");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$MemoryIndexReader");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl$5");
+    classes.add("org.apache.lucene.index.LogByteSizeMergePolicy");
+    classes.add("org.apache.lucene.queryParser.QueryParser$JJCalls");
+    classes.add("org.apache.lucene.search.PhraseQueue");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$ArrayIntList");
+    classes.add("org.apache.lucene.store.IndexInput");
+    classes.add("org.apache.lucene.index.memory.PatternAnalyzer$FastStringTokenizer");
+    classes.add("org.apache.lucene.search.FuzzyQuery$ScoreTermQueue");
+    classes.add("org.apache.lucene.index.SegmentInfos$FindSegmentsFile");
+    classes.add("org.apache.lucene.search.SortField");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$NameIs");
+    classes.add("org.apache.lucene.distributed.RMI$Return");
+    classes.add("org.apache.lucene.search.spans.NearSpansOrdered");
+    classes.add("org.apache.lucene.document.DateTools");
+    classes.add("org.apache.lucene.index.memory.SynonymMap");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$1");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndex");
+    classes.add("org.apache.lucene.index.SegmentMergeQueue");
+    classes.add("org.apache.lucene.distributed.RMI$ProxyKey");
+    classes.add("org.apache.lucene.index.DefaultSkipListWriter");
+    classes.add("org.apache.lucene.store.NoLockFactory");
+    classes.add("org.apache.lucene.search.FuzzyQuery");
+    classes.add("org.apache.lucene.index.BufferedDeletes$Num");
+    classes.add("org.apache.lucene.store.NoLock");
+    classes.add("org.apache.lucene.search.spans.SpanTermQuery");
+    classes.add("org.apache.lucene.index.FieldsReader$FieldForMerge");
+    classes.add("org.apache.lucene.search.ScoreDocComparator$1");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$6");
+    classes.add("org.apache.lucene.document.FieldSelectorResult");
+    classes.add("org.apache.lucene.search.function.CustomScoreQuery$CustomWeight");
+    classes.add("org.apache.lucene.ocean.Index$MergedDocMap$RI");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$AddWriteableMemoryDocumentsTask");
+    classes.add("org.apache.lucene.index.CompoundFileWriter");
+    classes.add("org.apache.lucene.ocean.util.XMLUtil$EmptyEntityResolver");
+    classes.add("org.apache.lucene.store.Directory");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$3");
+    classes.add("org.apache.lucene.search.function.ByteFieldSource$1");
+    classes.add("org.apache.lucene.ocean.DirectoryIndex");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$5");
+    classes.add("org.apache.lucene.search.PhrasePositions");
+    classes.add("org.apache.lucene.analysis.TeeTokenFilter");
+    classes.add("org.apache.lucene.analysis.WhitespaceTokenizer");
+    classes.add("org.apache.lucene.index.SegmentReader$FieldsReaderLocal");
+    classes.add("org.apache.lucene.store.RAMFile");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$NameEndsWith");
+    classes.add("org.apache.lucene.ocean.util.SortedList$SortedEntry");
+    classes.add("org.apache.lucene.search.QueryUtils$1");
+    classes.add("org.apache.lucene.ocean.util.XMLUtil$XMLException");
+    classes.add("org.apache.lucene.search.Scorer");
+    classes.add("org.apache.lucene.store.MMapDirectory");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermDocumentInformation");
+    classes.add("org.apache.lucene.search.MockFilter");
+    classes.add("org.apache.lucene.ocean.Snapshots");
+    classes.add("org.apache.lucene.document.Field$TermVector");
+    classes.add("org.apache.lucene.ocean.MultiThreadSearcherPolicy");
+    classes.add("org.apache.lucene.analysis.PerFieldAnalyzerWrapper");
+    classes.add("org.apache.lucene.analysis.ISOLatin1AccentFilter");
+    classes.add("org.apache.lucene.util.DocIdBitSet");
+    classes.add("org.apache.lucene.search.function.ByteFieldSource");
+    classes.add("org.apache.lucene.search.FieldCache$ByteParser");
+    classes.add("org.apache.lucene.distributed.NameService$Lease");
+    classes.add("org.apache.lucene.ocean.util.SortedList$EntryIterator");
+    classes.add("org.apache.lucene.search.spans.SpanNotQuery");
+    classes.add("org.apache.lucene.search.MultiPhraseQuery");
+    classes.add("org.apache.lucene.document.LoadFirstFieldSelector");
+    classes.add("org.apache.lucene.ocean.util.Util$ThreadLocalDateFormat");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$TokenStreamImpl");
+    classes.add("org.apache.lucene.store.Lock");
+    classes.add("org.apache.lucene.queryParser.QueryParserConstants");
+    classes.add("org.apache.lucene.index.FilterIndexReader$FilterTermEnum");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$2");
+    classes.add("org.apache.lucene.index.CorruptIndexException");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest$ModuloSinkTokenizer");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$2");
+    classes.add("org.apache.lucene.search.BooleanScorer2");
+    classes.add("org.apache.lucene.ThreadSafetyTest$IndexerThread");
+    classes.add("org.apache.lucene.ocean.Index$2");
+    classes.add("org.apache.lucene.search.QueryFilter");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedDocument");
+    classes.add("org.apache.lucene.search.spans.NearSpansOrdered$1");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$FieldInfo");
+    classes.add("org.apache.lucene.distributed.RMI$Server$InternalService");
+    classes.add("org.apache.lucene.util.cache.SimpleLRUCache$1");
+    classes.add("org.apache.lucene.index.IndexCommitPoint");
+    classes.add("org.apache.lucene.search.TimeLimitedCollector$TimerThread");
+    classes.add("org.apache.lucene.index.FieldsWriter");
+    classes.add("org.apache.lucene.store.MMapDirectory$MMapIndexInput");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$ContextThreadLocal");
+    classes.add("org.apache.lucene.index.memory.SynonymTokenFilter");
+    classes.add("org.apache.lucene.store.MyFile");
+    classes.add("org.apache.lucene.index.TermInfosReader");
+    classes.add("org.apache.lucene.index.MultipleTermPositions");
+    classes.add("org.apache.lucene.document.Document");
+    classes.add("org.apache.lucene.store.FSDirectory$FSIndexOutput");
+    classes.add("org.apache.lucene.index.MultiSegmentReader$MultiTermDocs");
+    classes.add("org.apache.lucene.ocean.DeletesResult$Result");
+    classes.add("org.apache.lucene.ocean.Transaction");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexWriter$1");
+    classes.add("org.apache.lucene.search.BooleanScorer$SubScorer");
+    classes.add("org.apache.lucene.search.MultiTermQuery");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$9");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil");
+    classes.add("org.apache.lucene.index.MergePolicy$MergeException");
+    classes.add("org.apache.lucene.index.MergePolicy$MergeSpecification");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl$3");
+    classes.add("org.apache.lucene.distributed.CLInterface");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$1");
+    classes.add("org.apache.lucene.index.IndexModifier");
+    classes.add("org.apache.lucene.search.function.IntFieldSource$1");
+    classes.add("org.apache.lucene.store.MockRAMOutputStream");
+    classes.add("org.apache.lucene.index.FilterIndexReader$FilterTermPositions");
+    classes.add("org.apache.lucene.search.DisjunctionSumScorer");
+    classes.add("org.apache.lucene.index.IndexFileDeleter$CommitPoint");
+    classes.add("org.apache.lucene.search.OceanMultiThreadSearcher$MultiSearcherThread");
+    classes.add("org.apache.lucene.distributed.RMI$Server$InternalService$Ref");
+    classes.add("org.apache.lucene.index.FieldsReader$LazyField");
+    classes.add("org.apache.lucene.distributed.RMI$ByteArrayWriteable");
+    classes.add("org.apache.lucene.index.ParallelReader$ParallelTermDocs");
+    classes.add("org.apache.lucene.ocean.DeletesResult");
+    classes.add("org.apache.lucene.store.instantiated.FieldSettings");
+    classes.add("org.apache.lucene.ocean.LargeBatchTransaction");
+    classes.add("org.apache.lucene.search.SpanFilter");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$AnnotatedWith");
+    classes.add("org.apache.lucene.search.PrefixFilter");
+    classes.add("org.apache.lucene.store.RAMDirectory");
+    classes.add("org.apache.lucene.ocean.util.Bytes$ByteArrayInputStream");
+    classes.add("org.apache.lucene.distributed.RMI");
+    classes.add("org.apache.lucene.search.ExtendedFieldCache");
+    classes.add("org.apache.lucene.ocean.DirectoryIndex$DirectoryIndexDeletionPolicy");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$2$1");
+    classes.add("org.apache.lucene.search.PhraseQuery$PhraseWeight");
+    classes.add("org.apache.lucene.index.MultiSegmentReader");
+    classes.add("org.apache.lucene.search.PrefixFilter$2");
+    classes.add("org.apache.lucene.distributed.index.IndexServiceImpl");
+    classes.add("org.apache.lucene.store.AlreadyClosedException");
+    classes.add("org.apache.lucene.ocean.util.OceanRandomAccessFile$FileOutputStream");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$Info");
+    classes.add("org.apache.lucene.index.TermFreqVector");
+    classes.add("org.apache.lucene.ocean.Index$IndexSnapshotSearchable");
+    classes.add("org.apache.lucene.index.DirectoryIndexReader$1");
+    classes.add("org.apache.lucene.index.ByteBlockPool$Allocator");
+    classes.add("org.apache.lucene.ocean.log.LogFileManager$RecordIterator");
+    classes.add("org.apache.lucene.search.function.CustomScoreQuery$CustomScorer");
+    classes.add("org.apache.lucene.index.MergePolicy$OneMerge");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$MemoryIndexReader$3");
+    classes.add("org.apache.lucene.index.ConcurrentMergeScheduler");
+    classes.add("org.apache.lucene.queryParser.MultiFieldQueryParser");
+    classes.add("org.apache.lucene.search.FilteredQuery$1");
+    classes.add("org.apache.lucene.search.MultiSearcher$1");
+    classes.add("org.apache.lucene.distributed.index.LuceneServer");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$5$1");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue");
+    classes.add("org.apache.lucene.ocean.util.DocumentSerializer");
+    classes.add("org.apache.lucene.search.function.ValueSourceQuery$ValueSourceWeight");
+    classes.add("org.apache.lucene.distributed.RMI$RMIClient");
+    classes.add("org.apache.lucene.store.MockRAMDirectory$Failure");
+    classes.add("org.apache.lucene.index.DirectoryIndexReader$ReaderCommit");
+    classes.add("org.apache.lucene.search.FieldCacheImpl");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$AnalyzerImpl");
+    classes.add("org.apache.lucene.index.MultiReader");
+    classes.add("org.apache.lucene.ocean.RamIndex$RamIndexSnapshot");
+    classes.add("org.apache.lucene.search.RemoteCachingWrapperFilter");
+    classes.add("org.apache.lucene.index.SegmentTermPositions");
+    classes.add("org.apache.lucene.util.Parameter");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermPositionVector");
+    classes.add("org.apache.lucene.ocean.util.LimitedFileInputStream");
+    classes.add("org.apache.lucene.search.ReqOptSumScorer");
+    classes.add("org.apache.lucene.search.Filter");
+    classes.add("org.apache.lucene.search.QueryTermVector");
+    classes.add("org.apache.lucene.search.ExtendedFieldCache$LongParser");
+    classes.add("org.apache.lucene.search.Explanation");
+    classes.add("org.apache.lucene.SearchTestForDuplicates");
+    classes.add("org.apache.lucene.index.PositionBasedTermVectorMapper$TVPositionInfo");
+    classes.add("org.apache.lucene.util.BitUtil");
+    classes.add("org.apache.lucene.search.SimilarityDelegator");
+    classes.add("org.apache.lucene.index.TermPositionVector");
+    classes.add("org.apache.lucene.search.BaseTestRangeFilter");
+    classes.add("org.apache.lucene.ocean.Index$MergedDocMap");
+    classes.add("org.apache.lucene.search.function.ReverseOrdFieldSource");
+    classes.add("org.apache.lucene.store.ChecksumIndexOutput");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$8");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$4");
+    classes.add("org.apache.lucene.search.OceanMultiThreadSearcher");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase");
+    classes.add("org.apache.lucene.search.ConjunctionScorer$1");
+    classes.add("org.apache.lucene.search.TopDocs");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$FileStreamData");
+    classes.add("org.apache.lucene.queryParser.CharStream");
+    classes.add("org.apache.lucene.search.spans.SpanScorer");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$4");
+    classes.add("org.apache.lucene.search.FilterManager$FilterItem");
+    classes.add("org.apache.lucene.analysis.TeeSinkTokenTest$3");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexWriter$FieldSetting");
+    classes.add("org.apache.lucene.store.SimpleFSLockFactory");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl$4");
+    classes.add("org.apache.lucene.store.LockReleaseFailedException");
+    classes.add("org.apache.lucene.store.NativeFSLock");
+    classes.add("org.apache.lucene.index.IndexReader$FieldOption");
+    classes.add("org.apache.lucene.search.BooleanClause");
+    classes.add("org.apache.lucene.ocean.IndexCreator$Add");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$ClassTest");
+    classes.add("org.apache.lucene.analysis.CharArraySet$CharArraySetIterator");
+    classes.add("org.apache.lucene.search.BooleanScorer$Collector");
+    classes.add("org.apache.lucene.ocean.util.Util");
+    classes.add("org.apache.lucene.store.IndexOutput");
+    classes.add("org.apache.lucene.search.ExtendedFieldCache$DoubleParser");
+    classes.add("org.apache.lucene.index.IndexDeletionPolicy");
+    classes.add("org.apache.lucene.index.Posting");
+    classes.add("org.apache.lucene.index.IndexFileDeleter");
+    classes.add("org.apache.lucene.index.memory.PatternAnalyzer");
+    classes.add("org.apache.lucene.search.FuzzyQuery$ScoreTerm");
+    classes.add("org.apache.lucene.store.ClassicFile");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction");
+    classes.add("org.apache.lucene.search.RemoteCachingWrapperFilterHelper");
+    classes.add("org.apache.lucene.analysis.PorterStemFilter");
+    classes.add("org.apache.lucene.ocean.snapshotlog.SnapshotLogFile");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl");
+    classes.add("org.apache.lucene.search.SpanFilterResult$PositionInfo");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$CRCInputStream");
+    classes.add("org.apache.lucene.search.QueryUtils$2");
+    classes.add("org.apache.lucene.search.TimeLimitedCollector$TimeExceededException");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermFreqVector");
+    classes.add("org.apache.lucene.search.SampleComparable$1");
+    classes.add("org.apache.lucene.distributed.index.SearchableService");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermPositions");
+    classes.add("org.apache.lucene.search.SpanFilterResult");
+    classes.add("org.apache.lucene.search.BooleanScorer");
+    classes.add("org.apache.lucene.store.ChannelFile");
+    classes.add("org.apache.lucene.search.function.ShortFieldSource$1");
+    classes.add("org.apache.lucene.ocean.Index$1");
+    classes.add("org.apache.lucene.search.ScoreDoc");
+    classes.add("org.apache.lucene.distributed.index.IndexService$Add");
+    classes.add("org.apache.lucene.queryParser.FastCharStream");
+    classes.add("org.apache.lucene.util.DocIdBitSet$DocIdBitSetIterator");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$IsA");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTerm");
+    classes.add("org.apache.lucene.index.MockIndexInput");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$DeletesTask");
+    classes.add("org.apache.lucene.distributed.RMI$Server$ClassServiceImpl");
+    classes.add("org.apache.lucene.ocean.util.RAMDirectorySerializer");
+    classes.add("org.apache.lucene.search.Hits");
+    classes.add("org.apache.lucene.index.FieldsReader");
+    classes.add("org.apache.lucene.ocean.MultiWriteableMemoryIndex");
+    classes.add("org.apache.lucene.index.TermVectorEntryFreqSortedComparator");
+    classes.add("org.apache.lucene.index.DocumentsWriterFieldMergeState");
+    classes.add("org.apache.lucene.util.cache.SimpleMapCache");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$Entry");
+    classes.add("org.apache.lucene.search.ConstantScoreQuery");
+    classes.add("org.apache.lucene.search.ConjunctionScorer");
+    classes.add("org.apache.lucene.store.BufferedIndexInput");
+    classes.add("org.apache.lucene.ocean.util.SortedList$KeyIterator");
+    classes.add("org.apache.lucene.store.VerifyingLockFactory$CheckedLock");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$11");
+    classes.add("org.apache.lucene.ocean.DirectoryMap");
+    classes.add("org.apache.lucene.index.MergeDocIDRemapper");
+    classes.add("org.apache.lucene.document.NumberTools");
+    classes.add("org.apache.lucene.search.Query");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile");
+    classes.add("org.apache.lucene.search.CheckHits$ExplanationAsserter");
+    classes.add("org.apache.lucene.search.spans.NearSpansUnordered$SpansCell");
+    classes.add("org.apache.lucene.index.TermPositions");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermDocs");
+    classes.add("org.apache.lucene.index.DocumentsWriterThreadState");
+    classes.add("org.apache.lucene.index.SegmentReader");
+    classes.add("org.apache.lucene.ocean.Batch");
+    classes.add("org.apache.lucene.IndexTest");
+    classes.add("org.apache.lucene.ocean.util.BytesPool$Entry");
+    classes.add("org.apache.lucene.index.memory.MemoryIndex$1");
+    classes.add("org.apache.lucene.search.BooleanQuery$1");
+    classes.add("org.apache.lucene.ocean.Batch$MasterBatch");
+    classes.add("org.apache.lucene.index.FieldReaderException");
+    classes.add("org.apache.lucene.index.BufferedDeletes");
+    classes.add("org.apache.lucene.search.DocIdSet");
+    classes.add("org.apache.lucene.analysis.StopFilter");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$FieldInfo");
+    classes.add("org.apache.lucene.search.SingleDocTestFilter");
+    classes.add("org.apache.lucene.index.SegmentMerger$1");
+    classes.add("org.apache.lucene.ocean.Index");
+    classes.add("org.apache.lucene.index.FieldInfo");
+    classes.add("org.apache.lucene.ocean.database.OceanDatabase$ActionResult");
+    classes.add("org.apache.lucene.index.ParallelReader");
+    classes.add("org.apache.lucene.distributed.Service");
+    classes.add("org.apache.lucene.ocean.util.XMLUtil");
+    classes.add("org.apache.lucene.search.Weight");
+    classes.add("org.apache.lucene.distributed.index.IndexService$Delete");
+    classes.add("org.apache.lucene.distributed.NameService");
+    classes.add("org.apache.lucene.search.ExtendedFieldCacheImpl$2");
+    classes.add("org.apache.lucene.store.ChannelFile$1");
+    classes.add("org.apache.lucene.analysis.LengthFilter");
+    classes.add("org.apache.lucene.search.WildcardQuery");
+    classes.add("org.apache.lucene.search.BooleanScorer2$SingleMatchScorer");
+    classes.add("org.apache.lucene.ocean.util.SortedList$Values");
+    classes.add("org.apache.lucene.store.ChannelPread");
+    classes.add("org.apache.lucene.search.BooleanScorer$BucketTable");
+    classes.add("org.apache.lucene.search.DisjunctionMaxQuery");
+    classes.add("org.apache.lucene.document.DateField");
+    classes.add("org.apache.lucene.search.function.OrdFieldSource$1");
+    classes.add("org.apache.lucene.search.spans.NearSpansUnordered$CellQueue");
+    classes.add("org.apache.lucene.ocean.TransactionSystem$LogFileDeleteTimer");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$8");
+    classes.add("org.apache.lucene.ocean.WriteableMemoryIndex$MemoryIndexSnapshot");
+    classes.add("org.apache.lucene.index.memory.AnalyzerUtil$5");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamOutput");
+    classes.add("org.apache.lucene.index.MultiLevelSkipListReader");
+    classes.add("org.apache.lucene.store.MockRAMInputStream");
+    classes.add("org.apache.lucene.ocean.util.Timeout");
+    classes.add("org.apache.lucene.search.function.ValueSource");
+    classes.add("org.apache.lucene.distributed.RMI$Invocation");
+    classes.add("org.apache.lucene.search.BooleanQuery$BooleanWeight");
+    classes.add("org.apache.lucene.analysis.LowerCaseTokenizer");
+    classes.add("org.apache.lucene.search.CachingWrapperFilter");
+    classes.add("org.apache.lucene.search.function.FieldScoreQuery");
+    classes.add("org.apache.lucene.util.UnicodeUtil");
+    classes.add("org.apache.lucene.analysis.KeywordTokenizer");
+    classes.add("org.apache.lucene.search.FuzzyTermEnum");
+    classes.add("org.apache.lucene.distributed.RMI$Server");
+    classes.add("org.apache.lucene.util.ToStringUtils");
+    classes.add("org.apache.lucene.util.SortedVIntList$SortedVIntListBuilder");
+    classes.add("org.apache.lucene.index.DocumentsWriter$ByteBlockAllocator");
+    classes.add("org.apache.lucene.distributed.RMI$TimerTask");
+    classes.add("org.apache.lucene.index.FilterIndexReader$FilterTermDocs");
+    classes.add("org.apache.lucene.document.Field$Index");
+    classes.add("org.apache.lucene.distributed.index.IndexService$Update");
+    classes.add("org.apache.lucene.search.DisjunctionMaxScorer");
+    classes.add("org.apache.lucene.search.ScoreDocComparator");
+    classes.add("org.apache.lucene.analysis.KeywordAnalyzer");
+    classes.add("org.apache.lucene.index.TermEnum");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedIndexReader");
+    classes.add("org.apache.lucene.index.SegmentReader$CopyOnWriteRef");
+    classes.add("org.apache.lucene.search.SloppyPhraseScorer$1");
+    classes.add("org.apache.lucene.analysis.CharTokenizer");
+    classes.add("org.apache.lucene.index.PostingVector");
+    classes.add("org.apache.lucene.index.SegmentInfo");
+    classes.add("org.apache.lucene.distributed.RMIClasses$SingleClassLoader");
+    classes.add("org.apache.lucene.index.CompoundFileReader$FileEntry");
+    classes.add("org.apache.lucene.search.function.FunctionTestSetup");
+    classes.add("org.apache.lucene.queryParser.QueryParser$Operator");
+    classes.add("org.apache.lucene.analysis.WordlistLoader");
+    classes.add("org.apache.lucene.index.PositionBasedTermVectorMapper");
+    classes.add("org.apache.lucene.index.TermDocs");
+    classes.add("org.apache.lucene.ocean.IndexID");
+    classes.add("org.apache.lucene.search.spans.SpanOrQuery$1");
+    classes.add("org.apache.lucene.analysis.SinkTokenizer");
+    classes.add("org.apache.lucene.search.MultiSearcher$CachedDfSource");
+    classes.add("org.apache.lucene.search.spans.Spans");
+    classes.add("org.apache.lucene.distributed.index.IndexService$IndexVersion");
+    classes.add("org.apache.lucene.distributed.RMIClasses$RMIObjectInputStream");
+    classes.add("org.apache.lucene.analysis.standard.StandardTokenizerImpl");
+    classes.add("org.apache.lucene.search.HitCollector");
+    classes.add("org.apache.lucene.index.ReusableStringReader");
+    classes.add("org.apache.lucene.search.BooleanQuery$TooManyClauses");
+    classes.add("org.apache.lucene.index.TermVectorsWriter");
+    classes.add("org.apache.lucene.index.MultipleTermPositions$IntQueue");
+    classes.add("org.apache.lucene.analysis.CachingTokenFilter");
+    classes.add("org.apache.lucene.distributed.RMI$Server$NameServiceImpl");
+    classes.add("org.apache.lucene.search.spans.SpanOrQuery");
+    classes.add("org.apache.lucene.store.FSDirectory");
+    classes.add("org.apache.lucene.search.PhraseQuery");
+    classes.add("org.apache.lucene.ocean.AbstractTransaction$IndexFailure");
+    classes.add("org.apache.lucene.index.TermVectorMapper");
+    classes.add("org.apache.lucene.index.MergePolicy");
+    classes.add("org.apache.lucene.index.DirectoryIndexReader");
+    classes.add("org.apache.lucene.index.TermInfo");
+    classes.add("org.apache.lucene.ocean.Index$IndexSnapshot");
+    classes.add("org.apache.lucene.index.IndexReader$2");
+    classes.add("org.apache.lucene.search.SpanQueryFilter");
+    classes.add("org.apache.lucene.ocean.util.CElement");
+    classes.add("org.apache.lucene.search.ExactPhraseScorer");
+    classes.add("org.apache.lucene.index.IndexThread");
+    classes.add("org.apache.lucene.store.ChannelTransfer");
+    classes.add("org.apache.lucene.search.CheckHits$1");
+    classes.add("org.apache.lucene.search.function.ValueSourceQuery");
+    classes.add("org.apache.lucene.store.RAMInputStream");
+    classes.add("org.apache.lucene.document.DateTools$Resolution");
+    classes.add("org.apache.lucene.ocean.OceanSearcher");
+    classes.add("org.apache.lucene.store.instantiated.FieldSetting");
+    classes.add("org.apache.lucene.ocean.Deletes");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermDocumentInformation$1");
+    classes.add("org.apache.lucene.ocean.log.LogFile$Record");
+    classes.add("org.apache.lucene.store.ChannelTransfer$1$1");
+    classes.add("org.apache.lucene.search.function.IntFieldSource");
+    classes.add("org.apache.lucene.search.MultiSearcherThread");
+    classes.add("org.apache.lucene.distributed.ResolverUtil$Test");
+    classes.add("org.apache.lucene.document.Field$Store");
+    classes.add("org.apache.lucene.distributed.RMIClasses$ClassKey");
+    classes.add("org.apache.lucene.ocean.FSDirectoryMap");
+    classes.add("org.apache.lucene.index.IndexWriter");
+    classes.add("org.apache.lucene.index.ByteSliceReader");
+    classes.add("org.apache.lucene.util.SmallFloat");
+    classes.add("org.apache.lucene.ocean.log.RecordData");
+    classes.add("org.apache.lucene.analysis.standard.StandardAnalyzer$SavedStreams");
+    classes.add("org.apache.lucene.search.function.DocValues");
+    classes.add("org.apache.lucene.document.SetBasedFieldSelector");
+    classes.add("org.apache.lucene.search.OceanMultiThreadSearcher$HitCollectorThread");
+    classes.add("org.apache.lucene.ocean.IndexCreator$Task");
+    classes.add("org.apache.lucene.search.CheckHits$ExplanationAssertingSearcher");
+    classes.add("org.apache.lucene.index.LogDocMergePolicy");
+    classes.add("org.apache.lucene.distributed.GetLuceneClasses$GenerateLuceneClassExclude");
+    classes.add("org.apache.lucene.search.ComplexExplanation");
+    classes.add("org.apache.lucene.search.function.FieldCacheSource");
+    classes.add("org.apache.lucene.ocean.SearcherPolicy");
+    classes.add("org.apache.lucene.ocean.log.LogFileManager");
+    classes.add("org.apache.lucene.search.TermQuery");
+    classes.add("org.apache.lucene.search.RangeQuery");
+    classes.add("org.apache.lucene.search.FilteredTermEnum");
+    classes.add("org.apache.lucene.ocean.log.RawLogFile$CRCException");
+    classes.add("org.apache.lucene.index.CompoundFileReader");
+    classes.add("org.apache.lucene.util.ScorerDocQueue");
+    classes.add("org.apache.lucene.index.ByteBlockPool");
+    classes.add("org.apache.lucene.index.memory.PatternAnalyzer$PatternTokenizer");
+    classes.add("org.apache.lucene.store._TestHelper");
+    classes.add("org.apache.lucene.ocean.util.Bytes");
+    classes.add("org.apache.lucene.ocean.util.OceanRandomAccessFile$FileInputStream");
+    classes.add("org.apache.lucene.ocean.IndexCreator");
+    classes.add("org.apache.lucene.index.ParallelArrayTermVectorMapper");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$1");
+    classes.add("org.apache.lucene.search.MultiSearcher");
+    classes.add("org.apache.lucene.search.QueryUtils");
+    classes.add("org.apache.lucene.store.instantiated.InstantiatedTermEnum");
+    classes.add("org.apache.lucene.analysis.standard.StandardFilter");
+    classes.add("org.apache.lucene.distributed.RMIClasses");
+    classes.add("org.apache.lucene.index.Term");
+    classes.add("org.apache.lucene.index.TermVectorOffsetInfo");
+    classes.add("org.apache.lucene.ocean.util.BytesPool$Timer");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$5");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$7");
+    classes.add("org.apache.lucene.analysis.Tokenizer");
+    classes.add("org.apache.lucene.search.TopFieldDocs");
+    classes.add("org.apache.lucene.index.KeepOnlyLastCommitDeletionPolicy");
+    classes.add("org.apache.lucene.ocean.log.RecordHeader");
+    classes.add("org.apache.lucene.search.BooleanScorer2$2");
+    classes.add("org.apache.lucene.store.ChannelPread$1");
+    classes.add("org.apache.lucene.search.DocIdSetIterator");
+    classes.add("org.apache.lucene.search.SampleComparable$2");
+    classes.add("org.apache.lucene.ocean.TransactionSystem$LargeBatch");
+    classes.add("org.apache.lucene.index.MultiSegmentReader$MultiTermPositions");
+    classes.add("org.apache.lucene.search.QueryUtils$3");
+    classes.add("org.apache.lucene.queryParser.QueryParserTokenManager");
+    classes.add("org.apache.lucene.ocean.DirectoryIndex$DirectoryIndexSnapshot");
+    classes.add("org.apache.lucene.search.FieldSortedHitQueue$3");
+    classes.add("org.apache.lucene.index.SegmentInfos$2");
+    classes.add("org.apache.lucene.search.spans.SpanNotQuery$1");
+    classes.add("org.apache.lucene.search.spans.SpanQuery");
+    classes.add("org.apache.lucene.analysis.LetterTokenizer");
+    classes.add("org.apache.lucene.index.IndexFileDeleter$RefCount");
+    classes.add("org.apache.lucene.search.IdGenerator");
+    classes.add("org.apache.lucene.search.FieldCacheImpl$12");
+    classes.add("org.apache.lucene.ocean.util.TokenStreamInput$FieldInfos");
+    classes.add("org.apache.lucene.index.OceanSegmentReader");
+  }}
\ No newline at end of file
Index: contrib/distributed/src/org/apache/lucene/distributed/NameService.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/NameService.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/NameService.java	(revision 0)
@@ -0,0 +1,26 @@
+package org.apache.lucene.distributed;
+
+import java.io.Serializable;
+
+public interface NameService {
+  public int getNumRefs(String service) throws Exception;
+  public String[] getNames() throws Exception;
+  public String renew(Lease lease) throws Exception;
+  
+  /**
+   * Creates refs to a service for use with distributed garbage collection
+   */
+  public static class Lease implements Serializable {
+    public String id;
+    public String service;
+    public long duration;
+    
+    public Lease(String id, String service, long duration) {
+      this.id = id;
+      this.service = service;
+      this.duration = duration;
+    }
+    
+    
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/ResolverUtil.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/ResolverUtil.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/ResolverUtil.java	(revision 0)
@@ -0,0 +1,509 @@
+package org.apache.lucene.distributed;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * <p>
+ * ResolverUtil is used to locate classes that are available in the/a class path
+ * and meet arbitrary conditions. The two most common conditions are that a
+ * class implements/extends another class, or that is it annotated with a
+ * specific annotation. However, through the use of the {@link Test} class it is
+ * possible to search using arbitrary conditions.
+ * </p>
+ * 
+ * <p>
+ * A ClassLoader is used to locate all locations (directories and jar files) in
+ * the class path that contain classes within certain packages, and then to load
+ * those classes and check them. By default the ClassLoader returned by
+ * {@code Thread.currentThread().getContextClassLoader()} is used, but this can
+ * be overridden by calling {@link #setClassLoader(ClassLoader)} prior to
+ * invoking any of the {@code find()} methods.
+ * </p>
+ * 
+ * <p>
+ * General searches are initiated by calling the
+ * {@link #find(com.opensymphony.xwork2.util.ResolverUtil.Test, String...)} ()}
+ * method and supplying a package name and a Test instance. This will cause the
+ * named package <b>and all sub-packages</b> to be scanned for classes that
+ * meet the test. There are also utility methods for the common use cases of
+ * scanning multiple packages for extensions of particular classes, or classes
+ * annotated with a specific annotation.
+ * </p>
+ * 
+ * <p>
+ * The standard usage pattern for the ResolverUtil class is as follows:
+ * </p>
+ * 
+ * <pre>
+ * esolverUtil&lt;ActionBean&gt; resolver = new ResolverUtil&lt;ActionBean&gt;();
+ * esolver.findImplementation(ActionBean.class, pkg1, pkg2);
+ * esolver.find(new CustomTest(), pkg1);
+ * esolver.find(new CustomTest(), pkg2);
+ * ollection&lt;ActionBean&gt; beans = resolver.getClasses();
+ * </pre>
+ * 
+ * <p>
+ * This class was copied from Stripes -
+ * http://stripes.mc4j.org/confluence/display/stripes/Home
+ * </p>
+ * 
+ * @author Tim Fennell
+ */
+public class ResolverUtil<T> {
+  PrintStream ERR = System.err;
+  /** An instance of Log to use for logging in this class. */
+  //private static final Logger LOG = LoggerFactory.getLogger(ResolverUtil.class);
+
+  /**
+   * A simple interface that specifies how to test classes to determine if they
+   * are to be included in the results produced by the ResolverUtil.
+   */
+  public static interface Test {
+    /**
+     * Will be called repeatedly with candidate classes. Must return True if a
+     * class is to be included in the results, false otherwise.
+     */
+    boolean matches(Class type);
+
+    boolean matches(URL resource);
+
+    boolean doesMatchClass();
+
+    boolean doesMatchResource();
+  }
+
+  public static abstract class ClassTest implements Test {
+    public boolean matches(URL resource) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean doesMatchClass() {
+      return true;
+    }
+
+    public boolean doesMatchResource() {
+      return false;
+    }
+  }
+
+  public static abstract class ResourceTest implements Test {
+    public boolean matches(Class cls) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean doesMatchClass() {
+      return false;
+    }
+
+    public boolean doesMatchResource() {
+      return true;
+    }
+  }
+
+  /**
+   * A Test that checks to see if each class is assignable to the provided
+   * class. Note that this test will match the parent type itself if it is
+   * presented for matching.
+   */
+  public static class IsA extends ClassTest {
+    private Class parent;
+
+    /**
+     * Constructs an IsA test using the supplied Class as the parent
+     * class/interface.
+     */
+    public IsA(Class parentType) {
+      this.parent = parentType;
+    }
+
+    /**
+     * Returns true if type is assignable to the parent type supplied in the
+     * constructor.
+     */
+    public boolean matches(Class type) {
+      return type != null && parent.isAssignableFrom(type);
+    }
+
+    @Override
+    public String toString() {
+      return "is assignable to " + parent.getSimpleName();
+    }
+  }
+
+  /**
+   * A Test that checks to see if each class name ends with the provided suffix.
+   */
+  public static class NameEndsWith extends ClassTest {
+    private String suffix;
+
+    /** Constructs a NameEndsWith test using the supplied suffix. */
+    public NameEndsWith(String suffix) {
+      this.suffix = suffix;
+    }
+
+    /**
+     * Returns true if type name ends with the suffix supplied in the
+     * constructor.
+     */
+    public boolean matches(Class type) {
+      return type != null && type.getName().endsWith(suffix);
+    }
+
+    @Override
+    public String toString() {
+      return "ends with the suffix " + suffix;
+    }
+  }
+
+  /**
+   * A Test that checks to see if each class is annotated with a specific
+   * annotation. If it is, then the test returns true, otherwise false.
+   */
+  public static class AnnotatedWith extends ClassTest {
+    private Class<? extends Annotation> annotation;
+
+    /** Construts an AnnotatedWith test for the specified annotation type. */
+    public AnnotatedWith(Class<? extends Annotation> annotation) {
+      this.annotation = annotation;
+    }
+
+    /**
+     * Returns true if the type is annotated with the class provided to the
+     * constructor.
+     */
+    public boolean matches(Class type) {
+      return type != null && type.isAnnotationPresent(annotation);
+    }
+
+    @Override
+    public String toString() {
+      return "annotated with @" + annotation.getSimpleName();
+    }
+  }
+
+  public static class NameIs extends ResourceTest {
+    private String name;
+
+    public NameIs(String name) {
+      this.name = "/" + name;
+    }
+
+    public boolean matches(URL resource) {
+      return (resource.getPath().endsWith(name));
+    }
+
+    @Override
+    public String toString() {
+      return "named " + name;
+    }
+  }
+
+  /** The set of matches being accumulated. */
+  private Set<Class<? extends T>> classMatches = new HashSet<Class<? extends T>>();
+
+  /** The set of matches being accumulated. */
+  private Set<URL> resourceMatches = new HashSet<URL>();
+
+  /**
+   * The ClassLoader to use when looking for classes. If null then the
+   * ClassLoader returned by Thread.currentThread().getContextClassLoader() will
+   * be used.
+   */
+  private ClassLoader classloader;
+
+  /**
+   * Provides access to the classes discovered so far. If no calls have been
+   * made to any of the {@code find()} methods, this set will be empty.
+   * 
+   * @return the set of classes that have been discovered.
+   */
+  public Set<Class<? extends T>> getClasses() {
+    return classMatches;
+  }
+
+  public Set<URL> getResources() {
+    return resourceMatches;
+  }
+
+  /**
+   * Returns the classloader that will be used for scanning for classes. If no
+   * explicit ClassLoader has been set by the calling, the context class loader
+   * will be used.
+   * 
+   * @return the ClassLoader that will be used to scan for classes
+   */
+  public ClassLoader getClassLoader() {
+    return classloader == null ? Thread.currentThread().getContextClassLoader() : classloader;
+  }
+
+  /**
+   * Sets an explicit ClassLoader that should be used when scanning for classes.
+   * If none is set then the context classloader will be used.
+   * 
+   * @param classloader
+   *          a ClassLoader to use when scanning for classes
+   */
+  public void setClassLoader(ClassLoader classloader) {
+    this.classloader = classloader;
+  }
+
+  /**
+   * Attempts to discover classes that are assignable to the type provided. In
+   * the case that an interface is provided this method will collect
+   * implementations. In the case of a non-interface class, subclasses will be
+   * collected. Accumulated classes can be accessed by calling
+   * {@link #getClasses()}.
+   * 
+   * @param parent
+   *          the class of interface to find subclasses or implementations of
+   * @param packageNames
+   *          one or more package names to scan (including subpackages) for
+   *          classes
+   */
+  public void findImplementations(Class parent, String... packageNames) {
+    if (packageNames == null)
+      return;
+
+    Test test = new IsA(parent);
+    for (String pkg : packageNames) {
+      findInPackage(test, pkg);
+    }
+  }
+
+  /**
+   * Attempts to discover classes who's name ends with the provided suffix.
+   * Accumulated classes can be accessed by calling {@link #getClasses()}.
+   * 
+   * @param suffix
+   *          The class name suffix to match
+   * @param packageNames
+   *          one or more package names to scan (including subpackages) for
+   *          classes
+   */
+  public void findSuffix(String suffix, String... packageNames) {
+    if (packageNames == null)
+      return;
+
+    Test test = new NameEndsWith(suffix);
+    for (String pkg : packageNames) {
+      findInPackage(test, pkg);
+    }
+  }
+
+  /**
+   * Attempts to discover classes that are annotated with to the annotation.
+   * Accumulated classes can be accessed by calling {@link #getClasses()}.
+   * 
+   * @param annotation
+   *          the annotation that should be present on matching classes
+   * @param packageNames
+   *          one or more package names to scan (including subpackages) for
+   *          classes
+   */
+  public void findAnnotated(Class<? extends Annotation> annotation, String... packageNames) {
+    if (packageNames == null)
+      return;
+
+    Test test = new AnnotatedWith(annotation);
+    for (String pkg : packageNames) {
+      findInPackage(test, pkg);
+    }
+  }
+
+  public void findNamedResource(String name, String... pathNames) {
+    if (pathNames == null)
+      return;
+
+    Test test = new NameIs(name);
+    for (String pkg : pathNames) {
+      findInPackage(test, pkg);
+    }
+  }
+
+  /**
+   * Attempts to discover classes that pass the test. Accumulated classes can be
+   * accessed by calling {@link #getClasses()}.
+   * 
+   * @param test
+   *          the test to determine matching classes
+   * @param packageNames
+   *          one or more package names to scan (including subpackages) for
+   *          classes
+   */
+  public void find(Test test, String... packageNames) {
+    if (packageNames == null)
+      return;
+
+    for (String pkg : packageNames) {
+      findInPackage(test, pkg);
+    }
+  }
+
+  /**
+   * Scans for classes starting at the package provided and descending into
+   * subpackages. Each class is offered up to the Test as it is discovered, and
+   * if the Test returns true the class is retained. Accumulated classes can be
+   * fetched by calling {@link #getClasses()}.
+   * 
+   * @param test
+   *          an instance of {@link Test} that will be used to filter classes
+   * @param packageName
+   *          the name of the package from which to start scanning for classes,
+   *          e.g. {@code net.sourceforge.stripes}
+   */
+  public void findInPackage(Test test, String packageName) {
+    packageName = packageName.replace('.', '/');
+    ClassLoader loader = getClassLoader();
+    Enumeration<URL> urls;
+
+    try {
+      urls = loader.getResources(packageName);
+    } catch (IOException ioe) {
+      ERR.println("Could not read package: " + packageName);
+      return;
+    }
+
+    while (urls.hasMoreElements()) {
+      try {
+        String urlPath = urls.nextElement().getFile();
+        urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+        // If it's a file in a directory, trim the stupid file: spec
+        if (urlPath.startsWith("file:")) {
+          urlPath = urlPath.substring(5);
+        }
+
+        // Else it's in a JAR, grab the path to the jar
+        if (urlPath.indexOf('!') > 0) {
+          urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+        }
+
+        ERR.println("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+        File file = new File(urlPath);
+        if (file.isDirectory()) {
+          loadImplementationsInDirectory(test, packageName, file);
+        } else {
+          loadImplementationsInJar(test, packageName, file);
+        }
+      } catch (IOException ioe) {
+        ERR.println("could not read entries");
+      }
+    }
+  }
+
+  /**
+   * Finds matches in a physical directory on a filesystem. Examines all files
+   * within a directory - if the File object is not a directory, and ends with
+   * <i>.class</i> the file is loaded and tested to see if it is acceptable
+   * according to the Test. Operates recursively to find classes within a folder
+   * structure matching the package structure.
+   * 
+   * @param test
+   *          a Test used to filter the classes that are discovered
+   * @param parent
+   *          the package name up to this directory in the package hierarchy.
+   *          E.g. if /classes is in the classpath and we wish to examine files
+   *          in /classes/org/apache then the values of <i>parent</i> would be
+   *          <i>org/apache</i>
+   * @param location
+   *          a File object representing a directory
+   */
+  private void loadImplementationsInDirectory(Test test, String parent, File location) {
+    File[] files = location.listFiles();
+    StringBuilder builder = null;
+
+    for (File file : files) {
+      builder = new StringBuilder(100);
+      builder.append(parent).append("/").append(file.getName());
+      String packageOrClass = (parent == null ? file.getName() : builder.toString());
+
+      if (file.isDirectory()) {
+        loadImplementationsInDirectory(test, packageOrClass, file);
+      } else if (isTestApplicable(test, file.getName())) {
+        addIfMatching(test, packageOrClass);
+      }
+    }
+  }
+
+  private boolean isTestApplicable(Test test, String path) {
+    return test.doesMatchResource() || path.endsWith(".class") && test.doesMatchClass();
+  }
+
+  /**
+   * Finds matching classes within a jar files that contains a folder structure
+   * matching the package structure. If the File is not a JarFile or does not
+   * exist a warning will be logged, but no error will be raised.
+   * 
+   * @param test
+   *          a Test used to filter the classes that are discovered
+   * @param parent
+   *          the parent package under which classes must be in order to be
+   *          considered
+   * @param jarfile
+   *          the jar file to be examined for classes
+   */
+  private void loadImplementationsInJar(Test test, String parent, File jarfile) {
+
+    try {
+      JarEntry entry;
+      JarInputStream jarStream = new JarInputStream(new FileInputStream(jarfile));
+
+      while ((entry = jarStream.getNextJarEntry()) != null) {
+        String name = entry.getName();
+        if (!entry.isDirectory() && name.startsWith(parent) && isTestApplicable(test, name)) {
+          addIfMatching(test, name);
+        }
+      }
+    } catch (IOException ioe) {
+      ERR.println("Could not search jar file '" + jarfile + "' for classes matching criteria: " + test + " due to an IOException");
+    }
+  }
+
+  /**
+   * Add the class designated by the fully qualified class name provided to the
+   * set of resolved classes if and only if it is approved by the Test supplied.
+   * 
+   * @param test
+   *          the test used to determine if the class matches
+   * @param fqn
+   *          the fully qualified name of a class
+   */
+  protected void addIfMatching(Test test, String fqn) {
+    try {
+      ClassLoader loader = getClassLoader();
+      if (test.doesMatchClass()) {
+        String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
+        //if (LOG.isDebugEnabled()) {
+        ERR.println("Checking to see if class " + externalName + " matches criteria [" + test + "]");
+        //}
+
+        Class type = loader.loadClass(externalName);
+        if (test.matches(type)) {
+          classMatches.add((Class<T>) type);
+        }
+      }
+      if (test.doesMatchResource()) {
+        URL url = loader.getResource(fqn);
+        if (url == null) {
+          url = loader.getResource(fqn.substring(1));
+        }
+        if (url != null && test.matches(url)) {
+          resourceMatches.add(url);
+        }
+      }
+    } catch (Throwable t) {
+      ERR.println("Could not examine class '" + fqn + "' due to a " + t.getClass().getName() + " with message: " + t.getMessage());
+    }
+  }
+}
\ No newline at end of file
Index: contrib/distributed/src/org/apache/lucene/distributed/RMI.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/RMI.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/RMI.java	(revision 0)
@@ -0,0 +1,646 @@
+package org.apache.lucene.distributed;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.net.SocketFactory;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.ipc.Client;
+import org.apache.lucene.distributed.NameService.Lease;
+import org.apache.lucene.distributed.RMIClasses.ClassAccept;
+import org.apache.lucene.distributed.RMIClasses.ClassKey;
+
+/*
+ * Base class for performing RMI over Hadoop RPC. Creates a server and allows
+ * for creation of proxy clients bound to a specific service. A service is a
+ * remote class defined by an interface.
+ * 
+ * A default service is ClassService which allows the loading of class bytes.
+ * This is used during the deserialization of a class on the Lucene server to
+ * dynamically load classes that are not a part of the core Lucene library such
+ * as those that subclass Query or Filter.
+ * 
+ * The RMI.Server.addService(String name, Object service) method allows defining
+ * a service by name with the server.
+ * 
+ */
+// TODO: implement service leases for dgc using softreferences on client
+// TODO: implement GUID for RMI
+// TODO: incoming call to server can set threadlocal of caller
+public class RMI {
+  private static Map<SocketFactory,Client> CLIENTS = new HashMap<SocketFactory,Client>();
+  Map<ProxyKey,RMIClient> rmiClientMap = new HashMap<ProxyKey,RMIClient>();
+  Map<Object,RMIClient> objRmiClientMap = new IdentityHashMap<Object,RMIClient>();
+  RMIClasses clientRmiClasses;
+  Server server;
+  SocketFactory socketFactory;
+  String localhost;
+  int port;
+  ClassAccept classAccept;
+  Configuration clientConf = new Configuration();
+  ReferenceQueue serviceRefQueue = new ReferenceQueue();
+  public static long LEASE_DURATION = 1000 * 10;
+  private ScheduledExecutorService ses;
+
+  public RMI(String bindAddress, int port, int numHandlers, ClassAccept classAccept) throws IOException {
+    socketFactory = SocketFactory.getDefault();
+    this.port = port;
+    localhost = bindAddress;// InetAddress.getLocalHost().getHostAddress();
+    this.classAccept = classAccept;
+    clientRmiClasses = new RMIClasses(classAccept);
+    Configuration conf = new Configuration();
+    server = new Server(conf, bindAddress, port, numHandlers, false);
+    ses = Executors.newSingleThreadScheduledExecutor();
+    ses.scheduleWithFixedDelay(new TimerTask(), LEASE_DURATION / 2, LEASE_DURATION / 2, TimeUnit.MILLISECONDS);
+  }
+
+  protected synchronized List<RMIClient> getRmiClients() {
+    return new ArrayList(rmiClientMap.values());
+  }
+
+  public class TimerTask implements Runnable {
+    public void run() {
+      List<RMIClient> list = getRmiClients();
+      for (RMIClient c : list) {
+        try {
+          c.renewLease();
+        } catch (Exception ex) {
+          ex.printStackTrace();
+          // System.out.println("renew lease: "+ex.getMessage());
+        }
+      }
+      server.removeExpiredRefs();
+      server.removeServicesWithNoRefs();
+    }
+  }
+
+  /**
+   * Allows distributed garbage collection to close a service
+   */
+  public static interface Closeable {
+    public void close() throws Exception;
+  }
+
+  public void close() {
+    for (Client client : CLIENTS.values()) {
+      client.stop();
+    }
+  }
+
+  public static class DefaultClassAccept implements ClassAccept {
+    Set<String> exclude;
+    Set<String> primitives = new HashSet<String>(10);
+
+    public DefaultClassAccept(Set<String> exclude) {
+      this.exclude = exclude;
+      primitives.add("int");
+      primitives.add("long");
+      primitives.add("double");
+      primitives.add("float");
+      primitives.add("byte");
+      primitives.add("boolean");
+      primitives.add("short");
+    }
+
+    public boolean isSpecial(String name) {
+      if (primitives.contains(name) || exclude.contains(name) || name.startsWith("java.")
+          || name.startsWith("org.apache.lucene.distributed") || name.startsWith("[")) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  public Server getServer() {
+    return server;
+  }
+
+  // doesn't work because socket isn't made until method call on service
+  public Object waitForProxy(String service, Class<?> protocol, long clientVersion, InetSocketAddress addr) throws IOException {
+    while (true) {
+      try {
+        return getProxy(service, protocol, clientVersion, addr);
+      } catch (ConnectException se) { // namenode has not been started
+        System.out.println("Server at " + addr + " not available yet, Zzzzz...");
+      } catch (SocketTimeoutException te) { // namenode is busy
+        System.out.println("Problem connecting to server: " + addr);
+      }
+      try {
+        Thread.sleep(1000);
+      } catch (InterruptedException ie) {
+        // IGNORE
+      }
+    }
+  }
+
+  public Object getProxy(ProxyKey proxyKey) throws IOException {
+    return getProxy(proxyKey.service, proxyKey.protocol, 1l, proxyKey.address);
+  }
+
+  public synchronized void clearOldProxies() {
+    while (true) {
+      Object service = serviceRefQueue.poll();
+      if (service != null) {
+        RMIClient rmiClient = objRmiClientMap.remove(service);
+        rmiClientMap.remove(rmiClient);
+      } else
+        break;
+    }
+  }
+
+  // TODO: match versions
+  public synchronized Object getProxy(String service, Class<?> protocol, long clientVersion, InetSocketAddress addr) throws IOException {
+    ProxyKey key = new ProxyKey(service, protocol, addr);
+    RMIClient rmiClient = rmiClientMap.get(key);
+    if (rmiClient == null) {
+      rmiClient = getRMIClient(service, protocol, addr);
+      rmiClient.proxy = Proxy.newProxyInstance(protocol.getClassLoader(), new Class[] { protocol }, rmiClient);
+      objRmiClientMap.put(rmiClient.proxy, rmiClient);
+      new SoftReference(rmiClient.proxy, serviceRefQueue);
+    }
+    return rmiClient.proxy;
+    // if (serverVersion == clientVersion) {
+    // return service;
+    // } else {
+    // throw new VersionMismatch(protocol.getName(), clientVersion,
+    // serverVersion);
+    // }
+  }
+
+  public static class ProxyKey implements Serializable {
+    String service;
+    InetSocketAddress address;
+    Class<?> protocol;
+
+    public ProxyKey(String service, Class<?> protocol, InetSocketAddress address) {
+      this.service = service;
+      this.protocol = protocol;
+      this.address = address;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((address == null) ? 0 : address.hashCode());
+      result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
+      result = prime * result + ((service == null) ? 0 : service.hashCode());
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      final ProxyKey other = (ProxyKey) obj;
+      if (address == null) {
+        if (other.address != null)
+          return false;
+      } else if (!address.equals(other.address))
+        return false;
+      if (protocol == null) {
+        if (other.protocol != null)
+          return false;
+      } else if (!protocol.equals(other.protocol))
+        return false;
+      if (service == null) {
+        if (other.service != null)
+          return false;
+      } else if (!service.equals(other.service))
+        return false;
+      return true;
+    }
+  }
+
+  public RMIClient getRMIClient(String service, Class<?> protocol, InetSocketAddress addr) throws IOException {
+    ProxyKey proxyKey = new ProxyKey(service, protocol, addr);
+    RMIClient rmiClient = rmiClientMap.get(proxyKey);
+    if (rmiClient == null) {
+      rmiClient = new RMIClient(service, addr, socketFactory);
+      rmiClientMap.put(proxyKey, rmiClient);
+    }
+    return rmiClient;
+  }
+
+  private synchronized Client getClient(Configuration conf, SocketFactory factory) {
+    Client client = CLIENTS.get(factory);
+    if (client == null) {
+      client = new Client(ByteArrayWriteable.class, conf, factory);
+      CLIENTS.put(factory, client);
+    }
+    return client;
+  }
+
+  public class RMIClient implements InvocationHandler {
+    Client client;
+    InetSocketAddress address;
+    String service;
+    private SocketFactory factory;
+    Object proxy;
+    NameService nameService;
+    String leaseId;
+
+    public RMIClient(String service, InetSocketAddress address, SocketFactory factory) throws IOException {
+      this.service = service;
+      this.address = address;
+      if (!service.equals("nameService"))
+        this.nameService = (NameService) getProxy("nameService", NameService.class, 1l, address);
+      this.factory = factory;
+    }
+
+    public void renewLease() throws Exception {
+      if (leaseId != null && leaseId.equals("no"))
+        return;
+      if (nameService != null) {
+        Lease lease = new Lease(leaseId, service, LEASE_DURATION);
+        leaseId = nameService.renew(lease);
+      }
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
+      synchronized (this) {
+        // create socket only when there is a call to the object
+        if (client == null) {
+          client = getClient(clientConf, factory);
+          client.setTimeout(1000 * 3 * 60);
+        }
+      }
+      long startTime = System.currentTimeMillis();
+      Invocation invocation = new Invocation(service, method, params);
+
+      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+      ObjectOutputStream objectOutput = clientRmiClasses.createOutput(byteOut);
+      objectOutput.writeObject(invocation);
+      objectOutput.flush();
+      ByteArrayWriteable bytesSent = new ByteArrayWriteable(localhost, port, byteOut.toByteArray());
+
+      ByteArrayWriteable bytesReturned = (ByteArrayWriteable) client.call(bytesSent, address);
+      ObjectInputStream objectInput = clientRmiClasses.createInput(bytesReturned.getInputStream(), RMI.this);
+      Object object = null;
+      try {
+        object = objectInput.readObject();
+      } catch (ClassNotFoundException cnfe) {
+        IOException ioException = new IOException();
+        ioException.initCause(cnfe);
+        throw ioException;
+      }
+      long callTime = System.currentTimeMillis() - startTime;
+      // LOG.debug("Call: " + method.getName() + " " + callTime);
+      Return r = (Return) object;
+      if (r.value != null)
+        return r.value;
+      else if (r.exception != null)
+        throw r.exception;
+      else
+        return null;
+    }
+  }
+
+  public static class ByteArrayWriteable implements Writable {
+    public String host;
+    public int port;
+    public byte[] bytes;
+
+    public ByteArrayWriteable() {
+    }
+
+    public ByteArrayWriteable(String host, int port, byte[] bytes) {
+      this.host = host;
+      this.port = port;
+      this.bytes = bytes;
+    }
+
+    public InputStream getInputStream() {
+      return new ByteArrayInputStream(bytes);
+    }
+
+    public void write(DataOutput out) throws IOException {
+      out.writeUTF(host);
+      out.writeInt(port);
+      out.writeInt(bytes.length);
+      out.write(bytes);
+    }
+
+    public void readFields(DataInput in) throws IOException {
+      host = in.readUTF();
+      port = in.readInt();
+      int length = in.readInt();
+      bytes = new byte[length];
+      in.readFully(bytes);
+    }
+  }
+
+  public static class Invocation implements Serializable {
+    public String service;
+    public String methodName;
+    public Object[] params;
+    public Class[] paramsClasses;
+
+    public Invocation(String service, Method method, Object[] params) {
+      this.service = service;
+      this.params = params;
+      this.methodName = method.getName();
+      this.paramsClasses = method.getParameterTypes();
+    }
+  }
+
+  public static class Return implements Serializable {
+    public Throwable exception;
+    public Object value;
+  }
+
+  public class Server extends org.apache.hadoop.ipc.Server {
+    Map<InetSocketAddress,ClassService> classServices = new HashMap<InetSocketAddress,ClassService>();
+    RMIClasses rmiClasses;
+    HashMap<String,InternalService> services = new HashMap<String,InternalService>();
+    IdentityHashMap<Object,String> serviceNames = new IdentityHashMap<Object,String>();
+    ReentrantLock servicesLock = new ReentrantLock();
+
+    public Server(Configuration conf, String bindAddress, int port) throws IOException {
+      this(conf, bindAddress, port, 5, false);
+    }
+
+    public Server(Configuration conf, String bindAddress, int port, int numHandlers, boolean verbose) throws IOException {
+      super(bindAddress, port, ByteArrayWriteable.class, numHandlers, conf);
+      rmiClasses = new RMIClasses(classAccept);
+      addService("classService", new ClassServiceImpl(), false);
+      addService("nameService", new NameServiceImpl(), false);
+      start();
+    }
+
+    public RMIClasses getRMIClasses() {
+      return rmiClasses;
+    }
+
+    public void removeServicesWithNoRefs() {
+      servicesLock.lock();
+      try {
+        Iterator<InternalService> iterator = services.values().iterator();
+        while (iterator.hasNext()) {
+          InternalService internalService = iterator.next();
+          if (internalService.getNumRefs() == 0 && internalService.dgc) {
+            if (internalService.service instanceof Closeable) {
+              Closeable closeable = (Closeable) internalService.service;
+              try {
+                closeable.close();
+              } catch (Exception ex) {
+                System.out.println(ex.getMessage());
+              }
+            }
+            iterator.remove();
+            System.out.println("removed dgc: " + internalService.name);
+            serviceNames.remove(internalService.service);
+          }
+        }
+      } finally {
+        servicesLock.unlock();
+      }
+    }
+
+    public void removeExpiredRefs() {
+      servicesLock.lock();
+      try {
+        long now = System.currentTimeMillis();
+        for (InternalService internalService : services.values()) {
+          if (internalService.dgc)
+            internalService.removeExpiredRefs(now);
+        }
+      } finally {
+        servicesLock.unlock();
+      }
+    }
+
+    public class InternalService {
+      public String name;
+      public Object service;
+      public Map<String,Ref> refs = new HashMap<String,Ref>();
+      public boolean dgc;
+
+      public InternalService(String name, Object service, boolean dgc) {
+        this.name = name;
+        this.service = service;
+        this.dgc = dgc;
+        if (dgc) {
+          // add default ref
+          refs.put("default", new Ref(System.currentTimeMillis() + (LEASE_DURATION / 2)));
+        }
+      }
+
+      public void removeExpiredRefs(long now) {
+        Iterator<Ref> iterator = refs.values().iterator();
+        while (iterator.hasNext()) {
+          Ref ref = iterator.next();
+          if (now > ref.expiration)
+            iterator.remove();
+        }
+      }
+
+      public String renew(String id, long duration) {
+        if (!dgc)
+          return "no";
+        Ref ref = null;
+        if (id != null)
+          ref = refs.get(id);
+        else {
+          id = UUID.randomUUID().toString();
+          ref = new Ref();
+          refs.put(id, ref);
+        }
+        ref.renew(duration);
+        return id;
+      }
+
+      public int getNumRefs() {
+        return refs.size();
+      }
+
+      public class Ref {
+        public long expiration;
+
+        public Ref() {
+        }
+
+        public Ref(long expiration) {
+          this.expiration = expiration;
+        }
+
+        public void renew(long duration) {
+          expiration = System.currentTimeMillis() + duration;
+        }
+      }
+    }
+
+    public String renewLease(String serviceName, String leaseId, long duration) {
+      System.out.println("renewLease " + serviceName + " " + leaseId + " " + duration);
+      InternalService is = services.get(serviceName);
+      return is.renew(leaseId, duration);
+    }
+
+    public void removeService(String name) {
+      servicesLock.lock();
+      try {
+        Object service = services.remove(name);
+        serviceNames.remove(service);
+      } finally {
+        servicesLock.unlock();
+      }
+    }
+
+    public RMI getRMI() {
+      return RMI.this;
+    }
+
+    public String getServiceName(Object service) {
+      servicesLock.lock();
+      try {
+        return serviceNames.get(service);
+      } finally {
+        servicesLock.unlock();
+      }
+    }
+
+    public class NameServiceImpl implements NameService {
+      public int getNumRefs(String service) throws Exception {
+        InternalService is = services.get(service);
+        if (is == null)
+          throw new Exception("unknown service: " + service);
+        return is.getNumRefs();
+      }
+
+      public String[] getNames() throws Exception {
+        servicesLock.lock();
+        try {
+          String[] names = services.keySet().toArray(new String[0]);
+          Arrays.sort(names);
+          return names;
+        } finally {
+          servicesLock.unlock();
+        }
+      }
+
+      public String renew(Lease lease) throws Exception {
+        return renewLease(lease.service, lease.id, lease.duration);
+      }
+    }
+
+    public class ClassServiceImpl implements ClassService {
+      public byte[] getResource(String resource) throws IOException {
+        InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
+        if (input == null)
+          return null;
+        return IOUtils.toByteArray(input);
+      }
+
+      public byte[] loadClassData(ClassKey classKey) throws IOException {
+        byte[] bytes = clientRmiClasses.loadClassData(classKey);
+        if (bytes == null) {
+          bytes = rmiClasses.loadClassData(classKey);
+        }
+        if (bytes == null) {
+          String resource = RMIClasses.classToResource(classKey.name);
+          bytes = getResource(resource);
+        }
+        return bytes;
+      }
+    }
+
+    public void addService(String name, Object service, boolean dgc) {
+      servicesLock.lock();
+      try {
+        services.put(name, new InternalService(name, service, dgc));
+        serviceNames.put(service, name);
+      } finally {
+        servicesLock.unlock();
+      }
+    }
+
+    public ClassService getClassService(InetSocketAddress addr) throws IOException {
+      // ClassService classService = classServices.get(addr);
+      // if (classService == null) {
+      return (ClassService) getProxy("classService", ClassService.class, ClassService.serialVersionUID, addr);
+      // classServices.put(addr, classService);
+      // }
+      // return classService;
+    }
+
+    protected ByteArrayWriteable toByteArrayWriteable(Object o) throws IOException {
+      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+      ObjectOutputStream objectOutput = rmiClasses.createOutput(byteOut, this);
+      objectOutput.writeObject(o);
+      objectOutput.flush();
+      return new ByteArrayWriteable(localhost, port, byteOut.toByteArray());
+    }
+
+    public Writable call(Writable param) throws IOException {
+      ByteArrayWriteable bytes = (ByteArrayWriteable) param;
+      ClassService classService = getClassService(new InetSocketAddress(bytes.host, bytes.port));
+      ObjectInputStream objectInput = rmiClasses.createInput(bytes.getInputStream(), classService);
+      Object sent = null;
+      try {
+        sent = objectInput.readObject();
+      } catch (ClassNotFoundException cnfe) {
+        IOException ioException = new IOException();
+        ioException.initCause(cnfe);
+        throw ioException;
+      }
+      Invocation invocation = (Invocation) sent;
+      try {
+        InternalService is = services.get(invocation.service);
+        System.out.println("invocation.service: " + invocation.service + " class: " + is.service.getClass().getName());
+        Method method = is.service.getClass().getMethod(invocation.methodName, invocation.paramsClasses);
+        long startTime = System.currentTimeMillis();
+        Object value = method.invoke(is.service, invocation.params);
+        Return r = new Return();
+        r.value = value;
+        return toByteArrayWriteable(r);
+        // return new ObjectWriteable(r, rmiClasses, classService);
+      } catch (InvocationTargetException e) {
+        Throwable target = e.getTargetException();
+        Return r = new Return();
+        r.exception = target;
+        return toByteArrayWriteable(r);
+      } catch (Throwable e) {
+        IOException ioe = new IOException(e.toString());
+        ioe.setStackTrace(e.getStackTrace());
+        throw ioe;
+      }
+    }
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/RMIClasses.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/RMIClasses.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/RMIClasses.java	(revision 0)
@@ -0,0 +1,330 @@
+package org.apache.lucene.distributed;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.rmi.Remote;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.lucene.distributed.RMI.ProxyKey;
+
+// TODO: need to load classes from jar names of classes that are in Lucene
+// and store as a text file
+// TODO: if class cannot be loaded from
+/**
+ * Offers object streaming with dynamic class loading.
+ * 
+ * The ClassKey holds the class name and serialVersionUID. The combination makes
+ * a class unique. This allows classes that have changed to be loading
+ * dynamically on deserialization in RMIObjectInputStream. This is because when
+ * a class changes, the serialVersionUID changes as well.
+ * 
+ * RMIObjectOutputStream records classes that are ok for ClassAccept.isSpecial
+ * in the classLoaders map. In the Lucene use case these would be subclasses of
+ * for example the Query class serialized on the client side.
+ * 
+ * RMIObjectInputStream dynamically loads classes that are ClassAccept.isSpecial
+ * from the the given CLInterface. If the class is new, a SingleClassLoader is
+ * created and placed into classLoaders.
+ * 
+ */
+public class RMIClasses implements CLInterface {
+  ConcurrentHashMap<ClassKey,ClassLoader> classLoaders = new ConcurrentHashMap<ClassKey,ClassLoader>();
+  ClassAccept classAccept;
+
+  public RMIClasses(ClassAccept classAccept) {
+    this.classAccept = classAccept;
+  }
+
+  public static interface ClassAccept {
+    public boolean isSpecial(String name);
+  }
+
+  public byte[] getResource(String resource) throws IOException {
+    throw new UnsupportedOperationException("");
+  }
+
+  public static String classToResource(String name) {
+    return name.replace('.', '/') + ".class";
+  }
+
+  public byte[] loadClassData(ClassKey classKey) throws IOException {
+    ClassLoader classLoader = classLoaders.get(classKey);
+    if (classLoader != null) {
+      String resource = classToResource(classKey.name);
+      InputStream input = classLoader.getResourceAsStream(resource);
+      return IOUtils.toByteArray(input);
+    } else
+      return null;
+  }
+  
+  public static Class getRemoteInterface(Class cl) {
+    Class[] is = cl.getInterfaces();
+    for (Class i : is) {
+      if (Remote.class.isAssignableFrom(i)) {
+        return i;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Maps a ClassKey to a ClassLoader. ClassLoader will only load the Class
+   * given by the ClassKey. The class bytes are read from CLInterface.
+   * 
+   */
+  public static class SingleClassLoader extends ClassLoader {
+    CLInterface clInterface;
+    ClassKey classKey;
+
+    public SingleClassLoader(ClassKey classKey, ClassLoader parent, CLInterface clInterface) {
+      super(parent);
+      this.classKey = classKey;
+      this.clInterface = clInterface;
+    }
+
+    public InputStream getResourceAsStream(String name) {
+      try {
+        return new ByteArrayInputStream(clInterface.getResource(name));
+      } catch (IOException ioException) {
+        throw new RuntimeException(ioException);
+      }
+    }
+
+    protected Class<?> findClass(final String name) throws ClassNotFoundException {
+      if (name.equals(classKey.name)) {
+        byte[] classData = null;
+        try {
+          classData = clInterface.loadClassData(classKey);
+        } catch (Exception exception) {
+          throw new ClassNotFoundException("", exception);
+        }
+        if (classData == null) {
+          throw new ClassNotFoundException(name);
+          //return super.findClass(name);
+        }
+        return defineClass(name, classData, 0, classData.length);
+      } else {
+        return super.findClass(name);
+      }
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+      Class c = findLoadedClass(name);
+      if (c == null) {
+        if (name.equals(classKey.name)) {
+          c = findClass(name);
+          if (resolve) {
+            resolveClass(c);
+          }
+          return c;
+        } else {
+          return super.loadClass(name, resolve);
+        }
+      }
+      return c;
+    }
+  }
+
+  public class RMIObjectOutputStream extends ObjectOutputStream {
+    private RMI.Server rmiServer;
+    private boolean writeClass;
+
+    public RMIObjectOutputStream(OutputStream output, RMI.Server rmiServer, boolean writeClass) throws IOException {
+      super(output);
+      this.rmiServer = rmiServer;
+      this.writeClass = writeClass;
+      if (rmiServer != null) {
+        enableReplaceObject(true);
+      }
+    }
+
+    /**
+     * Overridden to write out proxy key in place of service object if needed
+     */
+    protected Object replaceObject(Object obj) throws IOException {
+      assert rmiServer != null;
+      String name = rmiServer.getServiceName(obj);
+      if (name != null) {
+        RMI rmi = rmiServer.getRMI();
+        Class remoteInterface = getRemoteInterface(obj.getClass());
+        return new ProxyKey(name, remoteInterface, new InetSocketAddress(rmi.localhost, rmi.port));
+      } else {
+        return obj;
+      }
+    }
+
+    /**
+     * Marks class as one that may be loaded by the receiver if it's special
+     */
+    protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
+      String name = desc.getName();
+      if (classAccept.isSpecial(name)) {
+        Class cl = desc.forClass();
+        ClassKey classKey = new ClassKey(desc.getName(), desc.getSerialVersionUID());
+        if (!classLoaders.containsKey(classKey) && !cl.isPrimitive()) {
+          ClassLoader classLoader = cl.getClassLoader();
+          if (classLoader == null) {
+            assert classLoader != null;
+          }
+          classLoaders.put(classKey, classLoader);
+          if (writeClass) {
+            String resource = classToResource(name);
+            byte[] bytes = IOUtils.toByteArray(classLoader.getResourceAsStream(name));
+            writeInt(bytes.length);
+            write(bytes);
+          }
+        }
+      }
+      super.writeClassDescriptor(desc);
+    }
+  }
+
+  public RMIObjectOutputStream createOutput(OutputStream output) throws IOException {
+    return createOutput(output, null);
+  }
+
+  public RMIObjectOutputStream createOutput(OutputStream output, RMI.Server rmiServer) throws IOException {
+    return new RMIObjectOutputStream(output, rmiServer, false);
+  }
+  
+  public RMIObjectOutputStream createOutput(OutputStream output, RMI.Server rmiServer, boolean writeClasses) throws IOException {
+    return new RMIObjectOutputStream(output, rmiServer, writeClasses);
+  }
+
+  /**
+   * Used by the the RMIClient to insure that serialized proxies are handled
+   * 
+   * @param input
+   * @param rmi
+   * @return
+   * @throws IOException
+   */
+  public RMIObjectInputStream createInput(InputStream input, RMI rmi) throws IOException {
+    return new RMIObjectInputStream(input, null, rmi, false);
+  }
+  
+  public RMIObjectInputStream createInput(InputStream input, RMI rmi, boolean readClasses) throws IOException {
+    return new RMIObjectInputStream(input, null, rmi, readClasses);
+  }
+
+  public RMIObjectInputStream createInput(InputStream input, CLInterface clInterface) throws IOException {
+    return new RMIObjectInputStream(input, clInterface, null, false);
+  }
+
+  public class RMIObjectInputStream extends ObjectInputStream {
+    CLInterface clInterface;
+    RMI rmi;
+    boolean readClass;
+
+    public RMIObjectInputStream(InputStream input, CLInterface clInterface, RMI rmi, boolean readClass) throws IOException {
+      super(input);
+      this.clInterface = clInterface;
+      this.rmi = rmi;
+      this.readClass = readClass;
+      if (rmi != null) {
+        enableResolveObject(true);
+      }
+    }
+
+    protected Object resolveObject(Object obj) throws IOException {
+      if (obj instanceof ProxyKey) {
+        // transform to local rmi proxy
+        return rmi.getProxy((ProxyKey) obj);
+      } else {
+        return obj;
+      }
+    }
+
+    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+      String name = desc.getName();
+      if (!classAccept.isSpecial(name)) {
+        try {
+          return super.resolveClass(desc);
+        } catch (ClassNotFoundException ex) {
+          // could not find class locally, try loading it
+          throw new ClassNotFoundException(name);
+        }
+      }
+      CLInterface cli = clInterface;
+      long serialUID = desc.getSerialVersionUID();
+      if (readClass) {
+        int l = readInt();
+        final byte[] classBytes = new byte[l];
+        readFully(classBytes);
+        cli = new CLInterface() {
+          public byte[] getResource(String resource) throws IOException {
+            return classBytes;
+          }
+          public byte[] loadClassData(ClassKey classKey) throws IOException {
+            return classBytes;
+          }
+        };
+      }
+      ClassLoader classLoader = getClassLoader(new ClassKey(name, serialUID), cli);
+      if (classLoader == null)
+        return super.resolveClass(desc);
+      Class c = classLoader.loadClass(name);
+      if (c == null) {
+        throw new ClassNotFoundException(name);
+      }
+      return c;
+    }
+  }
+
+  public static class ClassKey implements Serializable {
+    public String name;
+    public long serialUID;
+
+    public ClassKey(String name, long serialUID) {
+      this.name = name;
+      this.serialUID = serialUID;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((name == null) ? 0 : name.hashCode());
+      result = prime * result + (int) (serialUID ^ (serialUID >>> 32));
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      final ClassKey other = (ClassKey) obj;
+      if (name == null) {
+        if (other.name != null)
+          return false;
+      } else if (!name.equals(other.name))
+        return false;
+      if (serialUID != other.serialUID)
+        return false;
+      return true;
+    }
+
+  }
+
+  public ClassLoader getClassLoader(ClassKey classKey, CLInterface clInterface) {
+    ClassLoader classLoader = classLoaders.get(classKey);
+    if (classLoader == null) {
+      ClassLoader parent = Thread.currentThread().getContextClassLoader();
+      classLoader = new SingleClassLoader(classKey, parent, clInterface);
+      classLoaders.put(classKey, classLoader);
+    }
+    return classLoader;
+  }
+}
Index: contrib/distributed/src/org/apache/lucene/distributed/Service.java
===================================================================
--- contrib/distributed/src/org/apache/lucene/distributed/Service.java	(revision 0)
+++ contrib/distributed/src/org/apache/lucene/distributed/Service.java	(revision 0)
@@ -0,0 +1,9 @@
+package org.apache.lucene.distributed;
+
+public class Service {
+  private String name;
+  
+  public String getName() {
+    return name;
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneClient.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneClient.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneClient.java	(revision 0)
@@ -0,0 +1,51 @@
+package org.apache.lucene.distributed.test;
+
+import java.net.InetSocketAddress;
+
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import org.apache.lucene.distributed.LuceneClasses;
+import org.apache.lucene.distributed.RMI;
+import org.apache.lucene.distributed.RMI.DefaultClassAccept;
+import org.apache.lucene.distributed.index.IndexService;
+import org.apache.lucene.distributed.index.LuceneClient;
+import org.apache.lucene.distributed.index.SearchableService;
+import org.apache.lucene.distributed.index.IndexManagerService.IndexSettings;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.MultiSearcher;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Searchable;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestLuceneClient extends LuceneTestCase {
+  public static void main(String args[]) throws Exception {
+    TestRunner.run(new TestSuite(TestLuceneClient.class));
+  }
+
+  public void testMain() throws Exception {
+    RMI rmi = new RMI("192.168.1.2", 9001, 2, new DefaultClassAccept(LuceneClasses.classes));
+    LuceneClient luceneClient = new LuceneClient(new InetSocketAddress("192.168.1.2", 9000), rmi);
+    IndexSettings indexSettings = new IndexSettings();
+    indexSettings.defaultAnalyzer = new WhitespaceAnalyzer();
+    IndexService indexService = luceneClient.indexManagerService.createIndex("test", indexSettings);
+    Document d = new Document();
+    d.add(new Field("text", "a b c i r i", Field.Store.YES, Field.Index.TOKENIZED));
+    indexService.addDocument(d, new WhitespaceAnalyzer());
+    indexService.flush();
+    SearchableService searchable = indexService.reopen();
+    MultiSearcher searcher = new MultiSearcher(new Searchable[] {searchable});
+    TopDocs topDocs = searcher.search(new MatchAllDocsQuery(), null, 10);
+    for (ScoreDoc sc : topDocs.scoreDocs) {
+      Document doc = searcher.doc(sc.doc);
+      System.out.println(doc.get("text"));
+    }
+    while (true) {
+      Thread.sleep(50);
+    }
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneServer.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneServer.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/test/TestLuceneServer.java	(revision 0)
@@ -0,0 +1,28 @@
+package org.apache.lucene.distributed.test;
+
+import java.io.File;
+
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.apache.lucene.distributed.LuceneClasses;
+import org.apache.lucene.distributed.RMI;
+import org.apache.lucene.distributed.RMI.DefaultClassAccept;
+import org.apache.lucene.distributed.index.LuceneServer;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestLuceneServer extends LuceneTestCase {
+  public static void main(String args[]) throws Exception {
+    TestRunner.run(new TestSuite(TestLuceneServer.class));
+  }
+
+  public void testMain() throws Exception {
+    File dir = new File("g:\\testluceneserver");
+    dir.mkdirs();
+    RMI rmi = new RMI("192.168.1.2", 9000, 2, new DefaultClassAccept(LuceneClasses.classes));
+    LuceneServer luceneServer = new LuceneServer(rmi, dir);
+    while (true) {
+      Thread.sleep(50);
+    }
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/TestClassLoader.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/TestClassLoader.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/TestClassLoader.java	(revision 0)
@@ -0,0 +1,118 @@
+package org.apache.lucene.distributed;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.lucene.distributed.RMI.DefaultClassAccept;
+import org.apache.lucene.distributed.RMIClasses.ClassKey;
+import org.apache.lucene.search.Query;
+
+public class TestClassLoader {
+  public static final String javacCmd = "G:\\jdk1.5.0_15\\bin\\javac.exe";
+  public static final String classPath = ".;G:\\oceanworkspace\\LuceneOcean\\bin"; // for use when compiling, needs to have Lucene classes
+  static File dir = new File("g:\\testclassloader"); // where output source and classes are compiled to
+  static Random random = new Random(System.currentTimeMillis());
+  static DefaultClassAccept classAccept = new DefaultClassAccept(LuceneClasses.classes);
+
+  public static void main(String[] args) throws Exception {
+    Instance i1 = new Instance(1);
+    Query q1 = testInput(i1);
+    Instance i2 = new Instance(2);
+    Query q2 = testInput(i2);
+    q2.toString(q1.toString());
+    // Instance i3 = new Instance(3);
+  }
+
+  public static Query testInput(Instance i1) throws Exception {
+    byte[] bytes = i1.serialize();
+    RMIClasses rc = new RMIClasses(classAccept);
+    ObjectInputStream objIn = rc.createInput(new ByteArrayInputStream(bytes), i1);
+    Query query = (Query) objIn.readObject();
+    System.out.println(query.toString(null));
+    return query;
+  }
+
+  public static class Instance implements CLInterface {
+    File srcFile;
+    File d;
+    RMIClasses classes;
+    Query query;
+
+    public Instance(int i) throws Exception {
+      d = new File(dir, i + "");
+      d.mkdirs();
+      srcFile = new File(d, "TP.java");
+      outputRandomSource((long)i, srcFile);
+      javac(d.getAbsolutePath(), srcFile.getAbsolutePath());
+      classes = new RMIClasses(classAccept);
+      ClassLoader cl = classes.getClassLoader(new ClassKey("TP", 1l), this);
+      Class c = cl.loadClass("TP");
+      query = (Query) c.newInstance();
+    }
+
+    public byte[] serialize() throws Exception {
+      System.out.println(query.toString(null));
+      ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+      ObjectOutputStream objOut = classes.createOutput(byteOut);
+      objOut.writeObject(query);
+      objOut.flush();
+      objOut.close();
+      return byteOut.toByteArray();
+    }
+
+    public byte[] getResource(String name) {
+      try {
+        File f = new File(d, name);
+        return FileUtils.readFileToByteArray(f);
+      } catch (IOException ioException) {
+        throw new RuntimeException(ioException);
+      }
+    }
+
+    public byte[] loadClassData(ClassKey classKey) throws IOException {
+      String resource = classKey.name.replace('.', '/') + ".class";
+      File f = new File(d, resource);
+      byte[] bytes = FileUtils.readFileToByteArray(f);
+      return bytes;
+    }
+  }
+
+  public static void javac(String outputDir, String source) throws IOException {
+    String cmd = javacCmd + " -d " + outputDir + " -cp "+classPath+" " + source;
+    Process process = Runtime.getRuntime().exec(cmd);
+    IOUtils.copy(process.getErrorStream(), System.err);
+    IOUtils.copy(process.getInputStream(), System.err);
+  }
+
+  public static void outputRandomSource(long id, File file) throws IOException {
+    StringBuilder b = new StringBuilder();
+    // b.append("package test;\n\n");
+    b.append("public class TP extends org.apache.lucene.search.Query {\n");
+    b.append("private static final long serialVersionUID = "+id+"l;\n");
+    StringBuilder tb = new StringBuilder();
+    for (int x = 0; x < 10; x++) {
+      tb.append(random.nextInt());
+    }
+    b.append("public String toString(String field) {\n");
+    b.append("  return \"" + tb.toString() + "\";\n");
+    b.append("}");
+    // b.append("public String text = \""+tb.toString()+"\";\n");
+    b.append("}");
+    FileUtils.writeStringToFile(file, b.toString());
+  }
+
+  public void testMain() throws Exception {
+    // RMIClasses classes1 = new RMIClasses(CLInterface clInterface);
+    // RMIClasses classes2 = new RMIClasses(CLInterface clInterface);
+
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/TestRMIClient.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/TestRMIClient.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/TestRMIClient.java	(revision 0)
@@ -0,0 +1,40 @@
+package org.apache.lucene.distributed;
+
+import java.net.InetSocketAddress;
+
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.lucene.distributed.RMI.DefaultClassAccept;
+import org.apache.lucene.distributed.TestClassLoader.Instance;
+import org.apache.lucene.util.LuceneTestCase;
+
+/**
+ * 1) Dynamically compiles custom Query class that overrides the toString(String field) 
+ * method to return a random string.  Calls TestService.search(Query) on a remote server
+ * which returns the random string.  
+ * 
+ * 2) Again compiles the Query class with a different random string and calls TestService.search(Query)
+ * if the string returned this time is different than 1) then the new query class was dynamically
+ * downloaded by the server. 
+ *
+ */
+public class TestRMIClient extends LuceneTestCase {
+  public static void main(String args[]) throws Exception {
+    TestRunner.run(new TestSuite(TestRMIClient.class));
+  }
+
+  public void testMain() throws Exception {
+    Instance i1 = new Instance(1);
+    RMI rmi2 = new RMI("192.168.1.2", 9001, 2, new DefaultClassAccept(LuceneClasses.classes));
+    TestService testService = (TestService) rmi2.waitForProxy("testService", TestService.class, 1, new InetSocketAddress("192.168.1.2",
+        9000));
+    String str1 = testService.search(i1.query);
+    System.out.println("str1: " + str1);
+
+    Instance i2 = new Instance(2);
+    String str2 = testService.search(i2.query);
+    System.out.println("str2: " + str2);
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/TestRMIServer.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/TestRMIServer.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/TestRMIServer.java	(revision 0)
@@ -0,0 +1,30 @@
+package org.apache.lucene.distributed;
+
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import org.apache.lucene.distributed.RMI.DefaultClassAccept;
+import org.apache.lucene.distributed.RMI.Server;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestRMIServer extends LuceneTestCase {
+  public static void main(String args[]) throws Exception {
+    TestRunner.run(new TestSuite(TestRMIServer.class));
+  }
+
+  public void testMain() throws Exception {
+    RMI rmi1 = new RMI("192.168.1.2", 9000, 2, new DefaultClassAccept(LuceneClasses.classes));
+    Server server = rmi1.getServer();
+    server.addService("testService", new TestServiceImpl(), false);
+    while (true) {
+      Thread.sleep(50);
+    }
+  }
+  
+  public class TestServiceImpl implements TestService {
+    public String search(Query query) throws Exception {
+      return query.toString(null);
+    }
+  }
+}
Index: contrib/distributed/test/org/apache/lucene/distributed/TestService.java
===================================================================
--- contrib/distributed/test/org/apache/lucene/distributed/TestService.java	(revision 0)
+++ contrib/distributed/test/org/apache/lucene/distributed/TestService.java	(revision 0)
@@ -0,0 +1,7 @@
+package org.apache.lucene.distributed;
+
+import org.apache.lucene.search.Query;
+
+public interface TestService {
+  public String search(Query query) throws Exception;
+}
Index: src/java/org/apache/lucene/analysis/Analyzer.java
===================================================================
--- src/java/org/apache/lucene/analysis/Analyzer.java	(revision 677992)
+++ src/java/org/apache/lucene/analysis/Analyzer.java	(working copy)
@@ -17,6 +17,7 @@
  * limitations under the License.
  */
 
+import java.io.ObjectStreamException;
 import java.io.Reader;
 import java.io.IOException;
 
@@ -27,7 +28,7 @@
  *  characters from the Reader into raw Tokens.  One or more TokenFilters may
  *  then be applied to the output of the Tokenizer.
  */
-public abstract class Analyzer {
+public abstract class Analyzer implements java.io.Serializable {
   /** Creates a TokenStream which tokenizes all the text in the provided
    * Reader.  Must be able to handle null field name for backward compatibility.
    */
@@ -44,8 +45,13 @@
     return tokenStream(fieldName, reader);
   }
 
-  private ThreadLocal tokenStreams = new ThreadLocal();
-
+  private transient ThreadLocal tokenStreams = new ThreadLocal();
+  
+  private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+    stream.defaultReadObject();
+    tokenStreams = new ThreadLocal();
+  }
+  
   /** Used by Analyzers that implement reusableTokenStream
    *  to retrieve previously saved TokenStreams for re-use
    *  by the same thread. */
