Index: pom.xml
===================================================================
--- pom.xml	(revision 25374)
+++ pom.xml	(working copy)
@@ -33,17 +33,26 @@
   <name>XWiki Platform - Plugins - Lucene search</name>
   <version>1.12-SNAPSHOT</version>
   <description>XWiki Platform - Plugins - Lucene search</description>
+  <properties>
+    <platform.core.version>2.0.1</platform.core.version>
+  </properties>
   <dependencies>
     <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>com.xpn.xwiki.platform</groupId>
       <artifactId>xwiki-core</artifactId>
-      <version>2.0.1</version>
+      <version>${platform.core.version}</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.lucene</groupId>
       <artifactId>lucene-core</artifactId>
-      <version>2.3.1</version>
+      <version>2.9.0</version>
     </dependency>
     <dependency>
       <groupId>commons-lang</groupId>
@@ -80,6 +89,21 @@
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
     </dependency>
+
+    <!-- Test dependencies -->
+    <dependency>
+      <groupId>org.xwiki.platform</groupId>
+      <artifactId>xwiki-core-shared-tests</artifactId>
+      <version>${platform.core.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.xpn.xwiki.platform</groupId>
+      <artifactId>xwiki-core</artifactId>
+      <version>${platform.core.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <!-- We must configure SCM in each module. For more information see:
        http://svn.xwiki.org/svnroot/xwiki/platform/pom/trunk/pom.xml -->
Index: src/test/java/com/xpn/xwiki/plugin/lucene/IndexUpdaterTest.java
===================================================================
--- src/test/java/com/xpn/xwiki/plugin/lucene/IndexUpdaterTest.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/plugin/lucene/IndexUpdaterTest.java	(revision 0)
@@ -0,0 +1,448 @@
+package com.xpn.xwiki.plugin.lucene;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.Date;
+import java.util.concurrent.Semaphore;
+
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.store.LockObtainFailedException;
+
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.store.XWikiStoreInterface;
+import com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.XWikiConfig;
+import com.xpn.xwiki.XWikiException;
+
+public class IndexUpdaterTest extends AbstractBridgedXWikiComponentTestCase
+{
+    /**
+     * @return the suite of tests being tested
+     */
+    public static Test suite()
+    {
+        return new TestSuite(IndexUpdaterTest.class);
+    }
+
+    public class TestXWiki extends XWiki
+    {
+        public XWikiStoreInterface getStore()
+        {
+            return new TestStore();
+        }
+
+        public XWikiDocument getDocument(String fullname, XWikiContext context)
+        {
+            System.out.println("Fullname: " + fullname);
+            return new LoremIpsum();
+        }
+
+        @Override
+        public XWikiConfig getConfig()
+        {
+            XWikiConfig p = new XWikiConfig();
+            p.setProperty(LucenePlugin.PROP_INDEX_DIR, IndexUpdaterTest.this.indexDir);
+
+            return p;
+        }
+
+        @Override
+        public boolean checkAccess(String action, XWikiDocument doc, XWikiContext context) throws XWikiException
+        {
+            System.out.println("Check access");
+
+            return true;
+        }
+    }
+
+    private class TestIndexRebuilder extends IndexRebuilder
+    {
+        TestIndexRebuilder(IndexUpdater indexUpdater, XWikiContext context, boolean needInitialRebuild)
+        {
+            super(indexUpdater, context, needInitialRebuild);
+        }
+
+        @Override
+        protected void initXWikiContainer(XWikiContext context)
+        {
+        }
+
+        @Override
+        protected void cleanupXWikiContainer(XWikiContext context)
+        {
+        }
+
+        @Override
+        public void run()
+        {
+            System.out.println("Running index rebuilder");
+            super.run();
+            IndexUpdaterTest.this.rebuildDone.release();
+        }
+
+    }
+
+    private class TestIndexUpdater extends IndexUpdater implements Runnable
+    {
+        TestIndexUpdater(Directory directory, int indexingInterval, int maxQueueSize, LucenePlugin plugin,
+            XWikiContext context)
+        {
+            super(directory, indexingInterval, maxQueueSize, plugin, context);
+        }
+
+        @Override
+        protected void initXWikiContainer(XWikiContext context)
+        {
+        }
+
+        @Override
+        protected void cleanupXWikiContainer(XWikiContext context)
+        {
+        }
+        
+        @Override
+        public void run()
+        {
+            System.out.println("Starting new thread: " + Thread.currentThread().getName());
+            if (Thread.currentThread().getName().equals("writerBlocker")) {
+                try {
+                    System.out.println("Holding directory lock for 5s.");
+                    IndexWriter writer = openWriter(true);
+                    Thread.sleep(5000);
+                    System.out.println("Releasing directory lock.");
+                    writer.close();
+                } catch (Exception e) {
+                }
+            } else if (Thread.currentThread().getName().equals("permanentBlocker")) {
+                try {
+                    System.out.println("Obtaining directory lock and waiting.");
+                    IndexWriter writer = openWriter(false);
+                    IndexUpdaterTest.this.writeBlockerAcquiresLock.release();
+                    IndexUpdaterTest.this.writeBlockerWait.acquireUninterruptibly();
+                    System.out.println("Releasing directory lock.");
+                    writer.close();
+                } catch (Exception e) {
+                }
+            } else {
+                super.run();
+            }
+        }
+    }
+
+    private class LoremIpsum extends XWikiDocument
+    {
+        public LoremIpsum()
+        {
+        }
+
+        @Override
+        public String getAuthor()
+        {
+            return "Cicero";
+        }
+
+        @Override
+        public String getCreator()
+        {
+            return "Cicero";
+        }
+
+        @Override
+        public Date getDate()
+        {
+            return new Date(0);
+        }
+
+        @Override
+        public Date getCreationDate()
+        {
+            return new Date(0);
+        }
+
+        @Override
+        public String getName()
+        {
+            return "Ipsum";
+        }
+
+        @Override
+        public String getDisplayTitle(XWikiContext context)
+        {
+            return "Lorem Ipsum";
+        }
+
+        @Override
+        public String getSpace()
+        {
+            return "Lorem";
+        }
+
+        @Override
+        public String getFullName()
+        {
+            return "Lorem.Ipsum";
+        }
+
+        @Override
+        public String getContent()
+        {
+            return "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+        }
+
+    }
+
+    private final static String indexDir = "target/lucenetest";
+
+    private final Semaphore rebuildDone = new Semaphore(0);
+
+    private final Semaphore writeBlockerWait = new Semaphore(0);
+
+    private final Semaphore writeBlockerAcquiresLock = new Semaphore(0);
+
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        
+        getContext().setWiki(new TestXWiki());
+        getContext().setDatabase("wiki");
+    }
+    
+    public void testCreateIndex() throws IOException
+    {
+        Directory directory = null;
+        File f = new File(indexDir);
+
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+        directory = FSDirectory.open(f);
+
+        int indexingInterval;
+        indexingInterval = 100;
+        int maxQueueSize;
+        maxQueueSize = 1000;
+
+        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
+        IndexUpdater indexUpdater = new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin, getContext());
+        IndexRebuilder indexRebuilder = new TestIndexRebuilder(indexUpdater, getContext(), true);
+
+        rebuildDone.acquireUninterruptibly();
+
+        assertTrue(IndexReader.indexExists(directory));
+    }
+
+    public void testIndexUpdater() throws Exception
+    {
+        File f = new File(indexDir);
+        Directory directory;
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+        directory = FSDirectory.open(f);
+
+        int indexingInterval;
+        indexingInterval = 100;
+        int maxQueueSize;
+        maxQueueSize = 1000;
+
+        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
+        IndexUpdater indexUpdater = new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin, getContext());
+        IndexRebuilder indexRebuilder = new TestIndexRebuilder(indexUpdater, getContext(), false);
+        Thread writerBlocker = new Thread(indexUpdater, "writerBlocker");
+        writerBlocker.start();
+        plugin.init(indexUpdater, indexRebuilder, getContext());
+
+        indexUpdater.cleanIndex();
+
+        Thread indexUpdaterThread = new Thread(indexUpdater, "Lucene Index Updater");
+        indexUpdaterThread.start();
+
+        indexUpdater.add(new LoremIpsum(), getContext());
+        indexUpdater.add(new LoremIpsum(), getContext());
+
+        try {
+            Thread.sleep(1000);
+            indexUpdater.doExit();
+        } catch (InterruptedException e) {
+        }
+        while (true) {
+            try {
+                indexUpdaterThread.join();
+                break;
+            } catch (InterruptedException e) {
+            }
+        }
+
+        Query q = new TermQuery(new Term(IndexFields.DOCUMENT_ID, "wiki:Lorem.Ipsum.default"));
+        IndexSearcher searcher = new IndexSearcher(directory, true);
+        TopDocs t = searcher.search(q, null, 10);
+
+        System.out.println("Searching for document id, number of hits: " + t.totalHits);
+
+        assertEquals(1, t.totalHits);
+
+        SearchResults results = plugin.getSearchResultsFromIndexes("Ipsum", "target/lucenetest", null, getContext());
+
+        assertEquals(1, results.getTotalHitcount());
+
+        System.out.println("Searching for 'Ipsum', number of hits: " + results.getTotalHitcount());
+        for (SearchResult result : results.getResults()) {
+            System.out.println("id: " + result.getId());
+        }
+    }
+
+    public void testLock() throws IOException
+    {
+        Directory directory;
+        File f = new File(indexDir);
+        int indexingInterval;
+        indexingInterval = 100;
+        int maxQueueSize;
+        maxQueueSize = 1000;
+
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+        directory = FSDirectory.open(f);
+
+        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
+
+        System.out.println("Creating new updater");
+
+        final IndexUpdater indexUpdater =
+                new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin, getContext());
+
+        plugin.init(indexUpdater, getContext());
+
+        Thread permanentBlocker = new Thread(indexUpdater, "permanentBlocker");
+        permanentBlocker.start();
+        writeBlockerAcquiresLock.acquireUninterruptibly();
+
+        assertTrue(IndexWriter.isLocked(indexUpdater.getDirectory()));
+
+        final boolean[] doneCleaningIndex = {false};
+
+        Thread indexCleaner = new Thread(new Runnable()
+        {
+            public void run()
+            {
+                try {
+                    indexUpdater.cleanIndex();
+                    System.out.println("Done cleaning index.");
+                    doneCleaningIndex[0] = true;
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, "indexCleaner");
+
+        indexCleaner.start();
+
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {
+        }
+
+        assertFalse(doneCleaningIndex[0]);
+
+        boolean wasActuallyLocked = false;
+
+        try {
+            if (!IndexWriter.isLocked(indexUpdater.getDirectory())) {
+                System.out.println("Not locked!");
+                IndexWriter w =
+                        new IndexWriter(indexUpdater.getDirectory(),
+                            new org.apache.lucene.analysis.standard.StandardAnalyzer());
+            } else {
+                wasActuallyLocked = true;
+            }
+            // assert(IndexWriter.isLocked(indexUpdater.getDirectory()));
+        } catch (LockObtainFailedException e) {
+            /*
+             * Strange, the isLocked method appears to be unreliable.
+             */
+            wasActuallyLocked = true;
+            System.out.println("Failed to obtain lock");
+        } catch (IOException e) {
+            assert (false);
+        }
+
+        assertTrue(wasActuallyLocked);
+
+        writeBlockerWait.release();
+
+        while (true) {
+            try {
+                indexCleaner.join();
+                break;
+            } catch (InterruptedException e) {
+            }
+        }
+
+        assertTrue(doneCleaningIndex[0]);
+
+        assertFalse(IndexWriter.isLocked(indexUpdater.getDirectory()));
+
+        IndexWriter w =
+                new IndexWriter(indexUpdater.getDirectory(), new org.apache.lucene.analysis.standard.StandardAnalyzer());
+        w.close();
+    }
+
+    public void testCleanLock() throws IOException
+    {
+        Directory directory;
+        File f = new File(indexDir);
+        int indexingInterval;
+        indexingInterval = 100;
+        int maxQueueSize;
+        maxQueueSize = 1000;
+
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+        directory = FSDirectory.open(f);
+
+        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
+
+        System.out.println("Creating new updater");
+
+        final IndexUpdater indexUpdater =
+                new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin, getContext());
+
+        plugin.init(indexUpdater, getContext());
+
+        Thread permanentBlocker = new Thread(indexUpdater, "permanentBlocker");
+        permanentBlocker.start();
+        writeBlockerAcquiresLock.acquireUninterruptibly();
+
+        try {
+            IndexWriter.unlock(indexUpdater.getDirectory());
+            // assert(!IndexWriter.isLocked(indexUpdater.getDirectory()));
+            IndexWriter w =
+                    new IndexWriter(indexUpdater.getDirectory(),
+                        new org.apache.lucene.analysis.standard.StandardAnalyzer());
+            w.close();
+
+        } catch (LockObtainFailedException e) {
+            // assert(false);
+            System.out.println("IndexWriter.unlock doesn't work!");
+        }
+
+        writeBlockerWait.release();
+    }
+}
Index: src/test/java/com/xpn/xwiki/plugin/lucene/TestStore.java
===================================================================
--- src/test/java/com/xpn/xwiki/plugin/lucene/TestStore.java	(revision 0)
+++ src/test/java/com/xpn/xwiki/plugin/lucene/TestStore.java	(revision 0)
@@ -0,0 +1,268 @@
+package com.xpn.xwiki.plugin.lucene;
+
+import com.xpn.xwiki.store.XWikiStoreInterface;
+import org.xwiki.query.QueryManager;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.doc.XWikiLink;
+import com.xpn.xwiki.doc.XWikiLock;
+import com.xpn.xwiki.objects.classes.BaseClass;
+
+import java.util.List;
+import java.util.LinkedList;
+
+public class TestStore implements XWikiStoreInterface
+{
+    public void saveXWikiDoc(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+    }
+
+    public void saveXWikiDoc(XWikiDocument doc, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+    }
+
+    public XWikiDocument loadXWikiDoc(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+
+        return null;
+    }
+
+    public void deleteXWikiDoc(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+    }
+
+    public List<String> getClassList(XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public List<String> searchDocumentsNames(String wheresql, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public int countDocuments(String wheresql, XWikiContext context) throws XWikiException
+    {
+        return 0;
+    }
+
+    public List<String> searchDocumentsNames(String wheresql, int nb, int start, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public List<String> searchDocumentsNames(String wheresql, int nb, int start, String selectColumns,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public List<String> searchDocumentsNames(String parametrizedSqlClause, int nb, int start,
+        List< ? > parameterValues, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public List<String> searchDocumentsNames(String parametrizedSqlClause, List< ? > parameterValues,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public int countDocuments(String parametrizedSqlClause, List< ? > parameterValues, XWikiContext context)
+        throws XWikiException
+    {
+        return 0;
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, int nb, int start, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, boolean customMapping,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, int nb, int start,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, int nb, int start,
+        List< ? > parameterValues, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, boolean customMapping,
+        int nb, int start, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, boolean customMapping,
+        boolean checkRight, int nb, int start, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, List< ? > parameterValues, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, boolean customMapping,
+        int nb, int start, List< ? > parameterValues, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, int nb, int start, List< ? > parameterValues,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public List<XWikiDocument> searchDocuments(String wheresql, boolean distinctbylanguage, boolean customMapping,
+        boolean checkRight, int nb, int start, List< ? > parameterValues, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<XWikiDocument>();
+    }
+
+    public XWikiLock loadLock(long docId, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+        return null;
+    }
+
+    public void saveLock(XWikiLock lock, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+    }
+
+    public void deleteLock(XWikiLock lock, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+    }
+
+    public List<XWikiLink> loadLinks(long docId, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+        return new LinkedList<XWikiLink>();
+    }
+
+    public List<String> loadBacklinks(String fullName, XWikiContext context, boolean bTransaction)
+        throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public void saveLinks(XWikiDocument doc, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+    }
+
+    public void deleteLinks(long docId, XWikiContext context, boolean bTransaction) throws XWikiException
+    {
+    }
+
+    public <T> List<T> search(String sql, int nb, int start, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<T>();
+    }
+
+    public <T> List<T> search(String sql, int nb, int start, List< ? > parameterValues, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<T>();
+    }
+
+    public <T> List<T> search(String sql, int nb, int start, Object[][] whereParams, XWikiContext context)
+        throws XWikiException
+    {
+        return new LinkedList<T>();
+    }
+
+    public <T> List<T> search(String sql, int nb, int start, Object[][] whereParams, List< ? > parameterValues,
+        XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<T>();
+    }
+
+    public void cleanUp(XWikiContext context)
+    {
+    }
+
+    public boolean isWikiNameAvailable(String wikiName, XWikiContext context) throws XWikiException
+    {
+        return false;
+    }
+
+    public void createWiki(String wikiName, XWikiContext context) throws XWikiException
+    {
+    }
+
+    public void deleteWiki(String wikiName, XWikiContext context) throws XWikiException
+    {
+    }
+
+    public boolean exists(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+        if (doc.getFullName().equals("Lorem.Ipsum"))
+            return true;
+        return false;
+    }
+
+    public boolean isCustomMappingValid(BaseClass bclass, String custommapping1, XWikiContext context)
+        throws XWikiException
+    {
+        return false;
+    }
+
+    public boolean injectCustomMapping(BaseClass doc1class, XWikiContext xWikiContext) throws XWikiException
+    {
+        return false;
+    }
+
+    public boolean injectCustomMappings(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+        return false;
+    }
+
+    public List<String> getCustomMappingPropertyList(BaseClass bclass)
+    {
+        return new LinkedList<String>();
+    }
+
+    public void injectCustomMappings(XWikiContext context) throws XWikiException
+    {
+    }
+
+    public void injectUpdatedCustomMappings(XWikiContext context) throws XWikiException
+    {
+    }
+
+    public List<String> getTranslationList(XWikiDocument doc, XWikiContext context) throws XWikiException
+    {
+        return new LinkedList<String>();
+    }
+
+    public QueryManager getQueryManager()
+    {
+        return null;
+    }
+}
Index: src/main/java/com/xpn/xwiki/plugin/lucene/ObjectData.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/ObjectData.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/ObjectData.java	(working copy)
@@ -1,220 +0,0 @@
-/*
- * See the NOTICE file distributed with this work for additional
- * information regarding copyright ownership.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package com.xpn.xwiki.plugin.lucene;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.lucene.document.Field;
-
-import com.xpn.xwiki.XWikiContext;
-import com.xpn.xwiki.doc.XWikiDocument;
-import com.xpn.xwiki.objects.BaseObject;
-import com.xpn.xwiki.objects.BaseProperty;
-import com.xpn.xwiki.objects.PropertyInterface;
-import com.xpn.xwiki.objects.classes.BaseClass;
-import com.xpn.xwiki.objects.classes.ListItem;
-import com.xpn.xwiki.objects.classes.PasswordClass;
-import com.xpn.xwiki.objects.classes.StaticListClass;
-
-/**
- * Hold the property values of the XWiki.ArticleClass Objects.
- */
-public class ObjectData extends IndexData
-{
-    private static final Log LOG = LogFactory.getLog(ObjectData.class);
-
-    public ObjectData(final XWikiDocument doc, final XWikiContext context)
-    {
-        super(doc, context);
-        setAuthor(doc.getAuthor());
-        setCreator(doc.getCreator());
-        setModificationDate(doc.getDate());
-        setCreationDate(doc.getCreationDate());
-    }
-
-    /**
-     * @see com.xpn.xwiki.plugin.lucene.IndexData#getType()
-     */
-    @Override
-    public String getType()
-    {
-        return LucenePlugin.DOCTYPE_OBJECTS;
-    }
-
-    @Override
-    public String getId()
-    {
-        return new StringBuffer(super.getId()).append(".objects").toString();
-    }
-
-    /**
-     * @return a string containing the result of {@link IndexData#getFullText(XWikiDocument,XWikiContext)}plus the full
-     *         text content (values of title,category,content and extract ) XWiki.ArticleClass Object, as far as it
-     *         could be extracted.
-     */
-    @Override
-    public String getFullText(XWikiDocument doc, XWikiContext context)
-    {
-        StringBuffer retval = new StringBuffer(super.getFullText(doc, context));
-        String contentText = getContentAsText(doc, context);
-        if (contentText != null) {
-            retval.append(" ").append(contentText).toString();
-        }
-        return retval.toString();
-    }
-
-    /**
-     * @return string containing value of title,category,content and extract of XWiki.ArticleClass
-     */
-    private String getContentAsText(XWikiDocument doc, XWikiContext context)
-    {
-        StringBuffer contentText = new StringBuffer();
-        try {
-            LOG.info(doc.getFullName());
-            for (String className : doc.getxWikiObjects().keySet()) {
-                for (BaseObject obj : doc.getObjects(className)) {
-                    extractContent(contentText, obj, context);
-                }
-            }
-        } catch (Exception e) {
-            LOG.error("error getting content from  XWiki Objects ", e);
-            e.printStackTrace();
-        }
-        return contentText.toString();
-    }
-
-    private void extractContent(StringBuffer contentText, BaseObject baseObject, XWikiContext context)
-    {
-        try {
-            if (baseObject != null) {
-                String[] propertyNames = baseObject.getPropertyNames();
-                for (String propertyName : propertyNames) {
-                    BaseProperty baseProperty = (BaseProperty) baseObject.getField(propertyName);
-                    if ((baseProperty != null) && (baseProperty.getValue() != null)) {
-                        PropertyInterface prop = baseObject.getxWikiClass(context).getField(propertyName);
-                        if (!(prop instanceof PasswordClass)) {
-                            contentText.append(baseProperty.getValue().toString());
-                        }
-                    }
-                    contentText.append(" ");
-                }
-            }
-        } catch (Exception e) {
-            LOG.error("error getting content from  XWiki Object ", e);
-            e.printStackTrace();
-        }
-    }
-
-    @Override
-    public void addDataToLuceneDocument(org.apache.lucene.document.Document luceneDoc, XWikiDocument doc,
-        XWikiContext context)
-    {
-        super.addDataToLuceneDocument(luceneDoc, doc, context);
-        for (String className : doc.getxWikiObjects().keySet()) {
-            for (BaseObject obj : doc.getObjects(className)) {
-                if (obj != null) {
-                    luceneDoc.add(new Field(IndexFields.OBJECT, obj.getClassName(), Field.Store.YES,
-                        Field.Index.TOKENIZED));
-                    Object[] propertyNames = obj.getPropertyNames();
-                    for (int i = 0; i < propertyNames.length; i++) {
-                        try {
-                            indexProperty(luceneDoc, obj, (String) propertyNames[i], context);
-                        } catch (Exception e) {
-                            LOG.error("error extracting fulltext for document " + this, e);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void indexProperty(org.apache.lucene.document.Document luceneDoc, BaseObject baseObject,
-        String propertyName, XWikiContext context)
-    {
-        String fieldFullName = baseObject.getClassName() + "." + propertyName;
-        BaseClass bClass = baseObject.getxWikiClass(context);
-        PropertyInterface prop = bClass.getField(propertyName);
-
-        if (prop instanceof PasswordClass) {
-            // Do not index passwords
-        } else if (prop instanceof StaticListClass && ((StaticListClass) prop).isMultiSelect()) {
-            indexStaticList(luceneDoc, baseObject, (StaticListClass) prop, propertyName, context);
-        } else {
-            final String ft = getContentAsText(baseObject, propertyName, context);
-            if (ft != null) {
-                luceneDoc.add(new Field(fieldFullName, ft, Field.Store.YES, Field.Index.TOKENIZED));
-            }
-        }
-    }
-
-    private void indexStaticList(org.apache.lucene.document.Document luceneDoc, BaseObject baseObject,
-        StaticListClass prop, String propertyName, XWikiContext context)
-    {
-        Map possibleValues = prop.getMap(context);
-        List keys = baseObject.getListValue(propertyName);
-        String fieldFullName = baseObject.getClassName() + "." + propertyName;
-        Iterator it = keys.iterator();
-        while (it.hasNext()) {
-            String value = (String) it.next();
-            ListItem item = (ListItem) possibleValues.get(value);
-            if (item != null) {
-                // we index the key of the list
-                String fieldName = fieldFullName + ".key";
-                luceneDoc.add(new Field(fieldName, item.getId(), Field.Store.YES, Field.Index.TOKENIZED));
-                // we index the value
-                fieldName = fieldFullName + ".value";
-                luceneDoc.add(new Field(fieldName, item.getValue(), Field.Store.YES, Field.Index.TOKENIZED));
-                if (!item.getId().equals(item.getValue())) {
-                    luceneDoc.add(new Field(fieldFullName, item.getValue(), Field.Store.YES, Field.Index.TOKENIZED));
-                }
-            }
-            // we index both if value is not equal to the id(key)
-            luceneDoc.add(new Field(fieldFullName, value, Field.Store.YES, Field.Index.TOKENIZED));
-        }
-    }
-
-    public String getFullText(XWikiDocument doc, BaseObject baseObject, String property, XWikiContext context)
-    {
-        return getContentAsText(baseObject, property, context);
-    }
-
-    private String getContentAsText(BaseObject baseObject, String property, XWikiContext context)
-    {
-        StringBuffer contentText = new StringBuffer();
-        try {
-            BaseProperty baseProperty;
-            baseProperty = (BaseProperty) baseObject.getField(property);
-            if (baseProperty.getValue() != null) {
-                PropertyInterface prop = baseObject.getxWikiClass(context).getField(property);
-                if (!(prop instanceof PasswordClass)) {
-                    contentText.append(baseProperty.getValue().toString());
-                }
-            }
-        } catch (Exception e) {
-            LOG.error("error getting content from  XWiki Objects ", e);
-            e.printStackTrace();
-        }
-        return contentText.toString();
-    }
-}
Index: src/main/java/com/xpn/xwiki/plugin/lucene/IndexRebuilder.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/IndexRebuilder.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/IndexRebuilder.java	(working copy)
@@ -49,17 +49,15 @@
  * </ul>
  * </li>
  * </ul>
- * The rebuild can be triggered using the {@link LucenePluginApi#rebuildIndex()} method of the
- * {@link LucenePluginApi}. Once a rebuild request is made, a new thread is created, so the
- * requesting script can continue processing, while the rebuilding is done in the background. The
- * actual indexing is done by the IndexUpdater thread, this thread just gathers the data and passes
- * it to the IndexUpdater.
+ * The rebuild can be triggered using the {@link LucenePluginApi#rebuildIndex()} method of the {@link LucenePluginApi}.
+ * Once a rebuild request is made, a new thread is created, so the requesting script can continue processing, while the
+ * rebuilding is done in the background. The actual indexing is done by the IndexUpdater thread, this thread just
+ * gathers the data and passes it to the IndexUpdater.
  * </p>
  * <p>
  * As a summary, this plugin:
  * <ul>
- * <li>cleans the Lucene search indexes and re-submits all the contents of all the wikis for
- * indexing</li>
+ * <li>cleans the Lucene search indexes and re-submits all the contents of all the wikis for indexing</li>
  * <li>without clogging the indexing thread (since 1.2)</li>
  * <li>all in a background thread (since 1.2)</li>
  * <li>making sure that only one rebuild is in progress (since 1.2)</li>
@@ -74,7 +72,7 @@
     private static final Log LOG = LogFactory.getLog(IndexRebuilder.class);
 
     /** The actual object/thread that indexes data. */
-    private IndexUpdater indexUpdater;
+    private final IndexUpdater indexUpdater;
 
     /** The XWiki context. */
     private XWikiContext context;
@@ -83,12 +81,12 @@
     private static int retryInterval = 30000;
 
     /** Variable used for indicating that a rebuild is already in progress. */
-    private boolean rebuildInProgress = false;
+    private volatile boolean rebuildInProgress = false;
 
-    public IndexRebuilder(IndexUpdater indexUpdater, XWikiContext context)
+    public IndexRebuilder(IndexUpdater indexUpdater, XWikiContext context, boolean needInitialBuild)
     {
         this.indexUpdater = indexUpdater;
-        if (indexUpdater.needInitialBuild) {
+        if (needInitialBuild) {
             this.startRebuildIndex(context);
             LOG.info("Launched initial lucene indexing");
         }
@@ -98,6 +96,7 @@
     {
         if (rebuildInProgress) {
             LOG.warn("Cannot launch rebuild because a build is in progress");
+
             return LucenePluginApi.REBUILD_IN_PROGRESS;
         } else {
             this.rebuildInProgress = true;
@@ -109,6 +108,7 @@
             indexRebuilderThread.setPriority(3);
             // Finally, start the rebuild in the background
             indexRebuilderThread.start();
+
             // Too bad that now we can't tell how many items are there to be indexed...
             return 0;
         }
@@ -148,11 +148,11 @@
             // automatically recreated by the velocity renderer, if it isn't found in the xcontext.
             context.remove("vcontext");
 
-            // Since this is where a new thread is created this is where we need to initialize the Container 
+            // Since this is where a new thread is created this is where we need to initialize the Container
             // ThreadLocal variables and not in the init() method. Otherwise we would simply overwrite the
             // Container values for the main thread...
             initXWikiContainer(context);
-            
+
             // The original request and response should not be used outside the actual request
             // processing thread, as they will be cleaned later by the container.
             context.setRequest(null);
@@ -172,16 +172,17 @@
             }
             MDC.remove("url");
         }
+
         LOG.debug("Lucene index rebuild done");
     }
 
     /**
-     * First empties the index, then fetches all Documents, their translations and their attachments
-     * for re-addition to the index.
+     * First empties the index, then fetches all Documents, their translations and their attachments for re-addition to
+     * the index.
      * 
      * @param context
-     * @return total number of documents and attachments successfully added to the indexer queue, -1
-     *         when errors occured.
+     * @return total number of documents and attachments successfully added to the indexer queue, -1 when errors
+     *         occured.
      */
     private int rebuildIndex(XWikiContext context) throws IOException
     {
@@ -224,6 +225,7 @@
     protected int indexWiki(String wikiName, XWikiContext context)
     {
         LOG.info("Reading content of wiki " + wikiName);
+        
         // Number of index entries processed
         int retval = 0;
         XWiki xwiki = context.getWiki();
@@ -235,9 +237,8 @@
             try {
                 docNames = xwiki.getStore().searchDocumentsNames("", context);
             } catch (XWikiException ex) {
-                LOG.warn(String.format(
-                    "Error getting document names for wiki [%s]. Internal error is: $s",
-                    wikiName, ex.getMessage()));
+                LOG.warn(String.format("Error getting document names for wiki [%s]. Internal error is: $s", wikiName,
+                    ex.getMessage()));
                 return -1;
             }
             for (String docName : docNames) {
@@ -246,6 +247,7 @@
                     document = xwiki.getDocument(docName, context);
                 } catch (XWikiException e2) {
                     LOG.error("error fetching document " + wikiName + ":" + docName, e2);
+                    
                     continue;
                 }
 
@@ -256,7 +258,7 @@
                     // rest of the platform, as the index rebuilder could fill the queue, and then a
                     // user trying to save a document would cause an exception. Thus, it is better
                     // to limit the index rebuilder thread only, and not the index updater.
-                    while (this.indexUpdater.getQueueSize() > this.indexUpdater.maxQueueSize) {
+                    while (this.indexUpdater.getQueueSize() > this.indexUpdater.getMaxQueueSize()) {
                         try {
                             // Don't leave any database connections open while sleeping
                             // This shouldn't be needed, but we never know what bugs might be there
@@ -270,11 +272,9 @@
                     retval++;
                     retval += addTranslationsOfDocument(document, context);
                     retval += this.indexUpdater.addAttachmentsOfDocument(document, context);
-                    retval += addObjectsOfDocument(document, context);
                 } else {
                     if (LOG.isInfoEnabled()) {
-                        LOG.info("XWiki delivered null for document name " + wikiName + ":"
-                            + docName);
+                        LOG.info("XWiki delivered null for document name " + wikiName + ":" + docName);
                     }
                 }
             }
@@ -285,22 +285,6 @@
         return retval;
     }
 
-    /**
-     * Getting the content(values of title/category/content/extract properties ) from the
-     * XWiki.ArticleClass objects
-     */
-    private int addObjectsOfDocument(XWikiDocument document, XWikiContext wikiContext)
-    {
-        int retval = 0;
-
-        if (document.hasElement(XWikiDocument.HAS_OBJECTS)) {
-            retval += document.getxWikiObjects().size();
-            this.indexUpdater.addObject(document, wikiContext);
-        }
-
-        return retval;
-    }
-
     protected int addTranslationsOfDocument(XWikiDocument document, XWikiContext wikiContext)
     {
         int retval = 0;
@@ -309,20 +293,18 @@
         try {
             translations = document.getTranslationList(wikiContext);
         } catch (XWikiException e) {
-            LOG.error("error getting list of translations from document "
-                + document.getFullName(), e);
-            e.printStackTrace();
+            LOG.error("error getting list of translations from document " + document.getFullName(), e);
+
             return 0;
         }
 
         for (String lang : translations) {
             try {
-                this.indexUpdater.add(document.getTranslatedDocument(lang, wikiContext),
-                    wikiContext);
+                this.indexUpdater.add(document.getTranslatedDocument(lang, wikiContext), wikiContext);
                 retval++;
             } catch (XWikiException e1) {
-                LOG.error("Error getting translated document for document "
-                    + document.getFullName() + " and language " + lang, e1);
+                LOG.error("Error getting translated document for document " + document.getFullName() + " and language "
+                    + lang, e1);
             }
         }
 
Index: src/main/java/com/xpn/xwiki/plugin/lucene/SearchResult.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/SearchResult.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/SearchResult.java	(working copy)
@@ -101,7 +101,7 @@
                 LOG.error("error retrieving url for attachment " + this.filename + " of document " + fullDocName);
                 e.printStackTrace();
             }
-        } else if (LucenePlugin.DOCTYPE_OBJECTS.equals(type)) {
+        } else {
             objects = doc.getValues("object");
         }
     }
@@ -246,8 +246,7 @@
      */
     public boolean isWikiContent()
     {
-        return (LucenePlugin.DOCTYPE_WIKIPAGE.equals(this.type) || LucenePlugin.DOCTYPE_ATTACHMENT.equals(this.type) || LucenePlugin.DOCTYPE_OBJECTS
-            .equals(this.type));
+        return (LucenePlugin.DOCTYPE_WIKIPAGE.equals(this.type) || LucenePlugin.DOCTYPE_ATTACHMENT.equals(this.type));
     }
 
 }
Index: src/main/java/com/xpn/xwiki/plugin/lucene/LucenePlugin.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/LucenePlugin.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/LucenePlugin.java	(working copy)
@@ -33,6 +33,7 @@
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.Term;
+import org.apache.lucene.index.CorruptIndexException;
 import org.apache.lucene.queryParser.MultiFieldQueryParser;
 import org.apache.lucene.queryParser.ParseException;
 import org.apache.lucene.queryParser.QueryParser;
@@ -46,6 +47,8 @@
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
 import org.xwiki.observation.ObservationManager;
 
 import com.xpn.xwiki.XWikiContext;
@@ -57,20 +60,17 @@
 import com.xpn.xwiki.web.Utils;
 
 /**
- * A plugin offering support for advanced searches using Lucene, a high performance, open source
- * search engine. It uses an {@link IndexUpdater} to monitor and submit wiki pages for indexing to
- * the Lucene engine, and offers simple methods for searching documents, with the possiblity to sort
- * by one or several document fields (besides the default sort by relevance), filter by one or
- * several languages, and search in one, several or all virtual wikis.
+ * A plugin offering support for advanced searches using Lucene, a high performance, open source search engine. It uses
+ * an {@link IndexUpdater} to monitor and submit wiki pages for indexing to the Lucene engine, and offers simple methods
+ * for searching documents, with the possiblity to sort by one or several document fields (besides the default sort by
+ * relevance), filter by one or several languages, and search in one, several or all virtual wikis.
  * 
  * @version $Id$
  */
-public class LucenePlugin extends XWikiDefaultPlugin implements XWikiPluginInterface
+public class LucenePlugin extends XWikiDefaultPlugin
 {
     public static final String DOCTYPE_WIKIPAGE = "wikipage";
 
-    public static final String DOCTYPE_OBJECTS = "objects";
-
     public static final String DOCTYPE_ATTACHMENT = "attachment";
 
     public static final String PROP_INDEX_DIR = "xwiki.plugins.lucene.indexdir";
@@ -81,14 +81,13 @@
 
     public static final String PROP_MAX_QUEUE_SIZE = "xwiki.plugins.lucene.maxQueueSize";
 
-    private static final String DEFAULT_ANALYZER =
-        "org.apache.lucene.analysis.standard.StandardAnalyzer";
+    private static final String DEFAULT_ANALYZER = "org.apache.lucene.analysis.standard.StandardAnalyzer";
 
     private static final Log LOG = LogFactory.getLog(LucenePlugin.class);
 
     /**
-     * The Lucene text analyzer, can be configured in <tt>xwiki.cfg</tt> using the key
-     * {@link #PROP_ANALYZER} (<tt>xwiki.plugins.lucene.analyzer</tt>).
+     * The Lucene text analyzer, can be configured in <tt>xwiki.cfg</tt> using the key {@link #PROP_ANALYZER} (
+     * <tt>xwiki.plugins.lucene.analyzer</tt>).
      */
     private Analyzer analyzer;
 
@@ -103,17 +102,16 @@
     protected Properties config;
 
     /**
-     * List of Lucene indexes used for searching. By default there is only one such index for all
-     * the wiki. One searches is created for each entry in {@link #indexDirs}.
+     * List of Lucene indexes used for searching. By default there is only one such index for all the wiki. One searches
+     * is created for each entry in {@link #indexDirs}.
      */
     private Searcher[] searchers;
 
     /**
-     * Comma separated list of directories holding Lucene index data. The first such directory is
-     * used by the internal indexer. Can be configured in <tt>xwiki.cfg</tt> using the key
-     * {@link #PROP_INDEX_DIR} (<tt>xwiki.plugins.lucene.indexdir</tt>). If no directory is
-     * configured, then a subdirectory <tt>lucene</tt> in the application's work directory is
-     * used.
+     * Comma separated list of directories holding Lucene index data. The first such directory is used by the internal
+     * indexer. Can be configured in <tt>xwiki.cfg</tt> using the key {@link #PROP_INDEX_DIR} (
+     * <tt>xwiki.plugins.lucene.indexdir</tt>). If no directory is configured, then a subdirectory <tt>lucene</tt> in
+     * the application's work directory is used.
      */
     private String indexDirs;
 
@@ -132,65 +130,60 @@
     protected void finalize() throws Throwable
     {
         LOG.error("Lucene plugin will exit !");
-        if (indexUpdater != null) {
-            indexUpdater.doExit();
+
+        if (this.indexUpdater != null) {
+            this.indexUpdater.doExit();
         }
 
         super.finalize();
     }
 
-    public synchronized int rebuildIndex(XWikiContext context)
+    public int rebuildIndex(XWikiContext context)
     {
-        return indexRebuilder.startRebuildIndex(context);
+        return this.indexRebuilder.startRebuildIndex(context);
     }
 
     /**
-     * Allows to search special named lucene indexes without having to configure them in
-     * <tt>xwiki.cfg</tt>. Slower than
-     * {@link #getSearchResults(String, String, String, String, XWikiContext)} since new index
-     * searcher instances are created for every query.
+     * Allows to search special named lucene indexes without having to configure them in <tt>xwiki.cfg</tt>. Slower than
+     * {@link #getSearchResults(String, String, String, String, XWikiContext)} since new index searcher instances are
+     * created for every query.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to
-     *            search.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to search.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws Exception If the index directories cannot be read, or the query is invalid.
      */
-    public SearchResults getSearchResultsFromIndexes(String query, String myIndexDirs,
-        String languages, XWikiContext context) throws Exception
+    public SearchResults getSearchResultsFromIndexes(String query, String myIndexDirs, String languages,
+        XWikiContext context) throws Exception
     {
-        Searcher[] mySearchers = createSearchers(myIndexDirs);
-        SearchResults retval =
-            search(query, (String) null, null, languages, mySearchers, context);
+        Searcher[] mySearchers = createSearchers(myIndexDirs, context);
+        SearchResults retval = search(query, (String) null, null, languages, mySearchers, context);
         closeSearchers(mySearchers);
 
         return retval;
     }
 
     /**
-     * Allows to search special named lucene indexes without having to configure them in xwiki.cfg.
-     * Slower than {@link #getSearchResults}since new index searcher instances are created for
-     * every query.
+     * Allows to search special named lucene indexes without having to configure them in xwiki.cfg. Slower than
+     * {@link #getSearchResults}since new index searcher instances are created for every query.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortFields A list of fields to sort results by. For each field, if the name starts
-     *            with '-', then that field (excluding the -) is used for reverse sorting. If
-     *            <tt>null</tt> or empty, sort by hit score.
-     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to
-     *            search.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortFields A list of fields to sort results by. For each field, if the name starts with '-', then that
+     *            field (excluding the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to search.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws Exception If the index directories cannot be read, or the query is invalid.
      */
-    public SearchResults getSearchResultsFromIndexes(String query, String[] sortFields,
-        String myIndexDirs, String languages, XWikiContext context) throws Exception
+    public SearchResults getSearchResultsFromIndexes(String query, String[] sortFields, String myIndexDirs,
+        String languages, XWikiContext context) throws Exception
     {
-        Searcher[] mySearchers = createSearchers(myIndexDirs);
+        Searcher[] mySearchers = createSearchers(myIndexDirs, context);
         SearchResults retval = search(query, sortFields, null, languages, mySearchers, context);
         closeSearchers(mySearchers);
 
@@ -198,27 +191,24 @@
     }
 
     /**
-     * Allows to search special named lucene indexes without having to configure them in
-     * <tt>xwiki.cfg</tt>. Slower than
-     * {@link #getSearchResults(String, String, String, String, XWikiContext)} since new index
-     * searcher instances are created for every query.
+     * Allows to search special named lucene indexes without having to configure them in <tt>xwiki.cfg</tt>. Slower than
+     * {@link #getSearchResults(String, String, String, String, XWikiContext)} since new index searcher instances are
+     * created for every query.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortField The name of a field to sort results by. If the name starts with '-', then
-     *            the field (excluding the -) is used for reverse sorting. If <tt>null</tt> or
-     *            empty, sort by hit score.
-     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to
-     *            search.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortField The name of a field to sort results by. If the name starts with '-', then the field (excluding
+     *            the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param myIndexDirs Comma separated list of directories containing the lucene indexes to search.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws Exception If the index directories cannot be read, or the query is invalid.
      */
-    public SearchResults getSearchResultsFromIndexes(String query, String sortField,
-        String myIndexDirs, String languages, XWikiContext context) throws Exception
+    public SearchResults getSearchResultsFromIndexes(String query, String sortField, String myIndexDirs,
+        String languages, XWikiContext context) throws Exception
     {
-        Searcher[] mySearchers = createSearchers(myIndexDirs);
+        Searcher[] mySearchers = createSearchers(myIndexDirs, context);
         SearchResults retval = search(query, sortField, null, languages, mySearchers, context);
         closeSearchers(mySearchers);
 
@@ -226,23 +216,21 @@
     }
 
     /**
-     * Searches all Indexes configured in <tt>xwiki.cfg</tt> (property
-     * <code>xwiki.plugins.lucene.indexdir</code>).
+     * Searches all Indexes configured in <tt>xwiki.cfg</tt> (property <code>xwiki.plugins.lucene.indexdir</code>).
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortField The name of a field to sort results by. If the name starts with '-', then
-     *            the field (excluding the -) is used for reverse sorting. If <tt>null</tt> or
-     *            empty, sort by hit score.
-     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be
-     *            <tt>null</tt> to search all virtual wikis.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortField The name of a field to sort results by. If the name starts with '-', then the field (excluding
+     *            the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be <tt>null</tt> to search
+     *            all virtual wikis.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @return The list of search results.
      * @param context The context of the request.
      * @throws Exception If the index directories cannot be read, or the query is invalid.
      */
-    public SearchResults getSearchResults(String query, String sortField,
-        String virtualWikiNames, String languages, XWikiContext context) throws Exception
+    public SearchResults getSearchResults(String query, String sortField, String virtualWikiNames, String languages,
+        XWikiContext context) throws Exception
     {
         // TODO Why is this here? This is slow, as it closes and opens indexes for each query.
         // openSearchers();
@@ -250,23 +238,21 @@
     }
 
     /**
-     * Searches all Indexes configured in <tt>xwiki.cfg</tt> (property
-     * <code>xwiki.plugins.lucene.indexdir</code>).
+     * Searches all Indexes configured in <tt>xwiki.cfg</tt> (property <code>xwiki.plugins.lucene.indexdir</code>).
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortField The name of a field to sort results by. If the name starts with '-', then
-     *            the field (excluding the -) is used for reverse sorting. If <tt>null</tt> or
-     *            empty, sort by hit score.
-     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be
-     *            <tt>null</tt> to search all virtual wikis.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortField The name of a field to sort results by. If the name starts with '-', then the field (excluding
+     *            the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be <tt>null</tt> to search
+     *            all virtual wikis.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @return The list of search results.
      * @param context The context of the request.
      * @throws Exception If the index directories cannot be read, or the query is invalid.
      */
-    public SearchResults getSearchResults(String query, String[] sortField,
-        String virtualWikiNames, String languages, XWikiContext context) throws Exception
+    public SearchResults getSearchResults(String query, String[] sortField, String virtualWikiNames, String languages,
+        XWikiContext context) throws Exception
     {
         return search(query, sortField, virtualWikiNames, languages, this.searchers, context);
     }
@@ -275,49 +261,45 @@
      * Creates and submits a query to the Lucene engine.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortField The name of a field to sort results by. If the name starts with '-', then
-     *            the field (excluding the -) is used for reverse sorting. If <tt>null</tt> or
-     *            empty, sort by hit score.
-     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be
-     *            <tt>null</tt> to search all virtual wikis.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortField The name of a field to sort results by. If the name starts with '-', then the field (excluding
+     *            the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be <tt>null</tt> to search
+     *            all virtual wikis.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param indexes List of Lucene indexes (searchers) to search.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws IOException If the Lucene searchers encounter a problem reading the indexes.
      * @throws ParseException If the query is not valid.
      */
-    private SearchResults search(String query, String sortField, String virtualWikiNames,
-        String languages, Searcher[] indexes, XWikiContext context) throws IOException,
-        ParseException
+    private SearchResults search(String query, String sortField, String virtualWikiNames, String languages,
+        Searcher[] indexes, XWikiContext context) throws IOException, ParseException
     {
         SortField sort = getSortField(sortField);
+
         // Perform the actual search
-        return search(query, (sort != null) ? new Sort(sort) : null, virtualWikiNames, languages,
-            indexes, context);
+        return search(query, (sort != null) ? new Sort(sort) : null, virtualWikiNames, languages, indexes, context);
     }
 
     /**
      * Creates and submits a query to the Lucene engine.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sortFields A list of fields to sort results by. For each field, if the name starts
-     *            with '-', then that field (excluding the -) is used for reverse sorting. If
-     *            <tt>null</tt> or empty, sort by hit score.
-     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be
-     *            <tt>null</tt> to search all virtual wikis.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sortFields A list of fields to sort results by. For each field, if the name starts with '-', then that
+     *            field (excluding the -) is used for reverse sorting. If <tt>null</tt> or empty, sort by hit score.
+     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be <tt>null</tt> to search
+     *            all virtual wikis.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param indexes List of Lucene indexes (searchers) to search.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws IOException If the Lucene searchers encounter a problem reading the indexes.
      * @throws ParseException If the query is not valid.
      */
-    private SearchResults search(String query, String[] sortFields, String virtualWikiNames,
-        String languages, Searcher[] indexes, XWikiContext context) throws IOException,
-        ParseException
+    private SearchResults search(String query, String[] sortFields, String virtualWikiNames, String languages,
+        Searcher[] indexes, XWikiContext context) throws IOException, ParseException
     {
         // Turn the sorting field names into SortField objects.
         SortField[] sorts = null;
@@ -333,53 +315,48 @@
                 sorts = (SortField[]) ArrayUtils.removeElement(sorts, null);
             }
         }
+
         // Perform the actual search
-        return search(query, (sorts != null) ? new Sort(sorts) : null, virtualWikiNames,
-            languages, indexes, context);
+        return search(query, (sorts != null) ? new Sort(sorts) : null, virtualWikiNames, languages, indexes, context);
     }
 
     /**
      * Creates and submits a query to the Lucene engine.
      * 
      * @param query The base query, using the query engine supported by Lucene.
-     * @param sort A Lucene sort object, can contain one or more sort criterias. If <tt>null</tt>,
-     *            sort by hit score.
-     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be
-     *            <tt>null</tt> to search all virtual wikis.
-     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt>
-     *            or empty to search all languages.
+     * @param sort A Lucene sort object, can contain one or more sort criterias. If <tt>null</tt>, sort by hit score.
+     * @param virtualWikiNames Comma separated list of virtual wiki names to search in, may be <tt>null</tt> to search
+     *            all virtual wikis.
+     * @param languages Comma separated list of language codes to search in, may be <tt>null</tt> or empty to search all
+     *            languages.
      * @param indexes List of Lucene indexes (searchers) to search.
      * @param context The context of the request.
      * @return The list of search results.
      * @throws IOException If the Lucene searchers encounter a problem reading the indexes.
      * @throws ParseException If the query is not valid.
      */
-    private SearchResults search(String query, Sort sort, String virtualWikiNames,
-        String languages, Searcher[] indexes, XWikiContext context) throws IOException,
-        ParseException
+    private SearchResults search(String query, Sort sort, String virtualWikiNames, String languages,
+        Searcher[] indexes, XWikiContext context) throws IOException, ParseException
     {
         MultiSearcher searcher = new MultiSearcher(indexes);
         // Enhance the base query with wiki names and languages.
         Query q = buildQuery(query, virtualWikiNames, languages);
         // Perform the actual search
         Hits hits = (sort == null) ? searcher.search(q) : searcher.search(q, sort);
-        final int hitcount = hits.length();
         if (LOG.isDebugEnabled()) {
-            LOG.debug("query " + q + " returned " + hitcount + " hits");
+            LOG.debug("query " + q + " returned " + hits.length() + " hits");
         }
+
         // Transform the raw Lucene search results into XWiki-aware results
-        return new SearchResults(hits,
-            new com.xpn.xwiki.api.XWiki(context.getWiki(), context),
-            context);
+        return new SearchResults(hits, new com.xpn.xwiki.api.XWiki(context.getWiki(), context), context);
     }
 
     /**
-     * Create a {@link SortField} corresponding to the field name. If the field name starts with
-     * '-', then the field (excluding the leading -) will be used for reverse sorting.
+     * Create a {@link SortField} corresponding to the field name. If the field name starts with '-', then the field
+     * (excluding the leading -) will be used for reverse sorting.
      * 
-     * @param sortField The name of the field to sort by. If <tt>null</tt>, return a
-     *            <tt>null</tt> SortField. If starts with '-', then return a SortField that does a
-     *            reverse sort on the field.
+     * @param sortField The name of the field to sort by. If <tt>null</tt>, return a <tt>null</tt> SortField. If starts
+     *            with '-', then return a SortField that does a reverse sort on the field.
      * @return A SortFiled that sorts on the given field, or <tt>null</tt>.
      */
     private SortField getSortField(String sortField)
@@ -392,17 +369,16 @@
                 sort = new SortField(sortField);
             }
         }
+
         return sort;
     }
 
     /**
      * @param query
      * @param virtualWikiNames comma separated list of virtual wiki names
-     * @param languages comma separated list of language codes to search in, may be null to search
-     *            all languages
+     * @param languages comma separated list of language codes to search in, may be null to search all languages
      */
-    private Query buildQuery(String query, String virtualWikiNames, String languages)
-        throws ParseException
+    private Query buildQuery(String query, String virtualWikiNames, String languages) throws ParseException
     {
         // build a query like this: <user query string> AND <wikiNamesQuery> AND
         // <languageQuery>
@@ -433,12 +409,10 @@
         }
 
         if (virtualWikiNames != null && virtualWikiNames.length() > 0) {
-            bQuery.add(buildOredTermQuery(virtualWikiNames, IndexFields.DOCUMENT_WIKI),
-                BooleanClause.Occur.MUST);
+            bQuery.add(buildOredTermQuery(virtualWikiNames, IndexFields.DOCUMENT_WIKI), BooleanClause.Occur.MUST);
         }
         if (languages != null && languages.length() > 0) {
-            bQuery.add(buildOredTermQuery(languages, IndexFields.DOCUMENT_LANGUAGE),
-                BooleanClause.Occur.SHOULD);
+            bQuery.add(buildOredTermQuery(languages, IndexFields.DOCUMENT_LANGUAGE), BooleanClause.Occur.SHOULD);
         }
 
         return bQuery;
@@ -455,9 +429,9 @@
             // build a query like this: <valueArray[0]> OR <valueArray[1]> OR ...
             BooleanQuery orQuery = new BooleanQuery();
             for (int i = 0; i < valueArray.length; i++) {
-                orQuery.add(new TermQuery(new Term(fieldname, valueArray[i].trim())),
-                    BooleanClause.Occur.SHOULD);
+                orQuery.add(new TermQuery(new Term(fieldname, valueArray[i].trim())), BooleanClause.Occur.SHOULD);
             }
+
             return orQuery;
         }
 
@@ -467,38 +441,108 @@
 
     public synchronized void init(XWikiContext context)
     {
-        super.init(context);
         if (LOG.isDebugEnabled()) {
             LOG.debug("lucene plugin: in init");
         }
-        config = context.getWiki().getConfig();
+        this.config = context.getWiki().getConfig();
+
+        this.indexDirs = this.config.getProperty(PROP_INDEX_DIR);
+        if (StringUtils.isEmpty(this.indexDirs)) {
+            File workDir = context.getWiki().getWorkSubdirectory("lucene", context);
+            this.indexDirs = workDir.getAbsolutePath();
+        }
+        String indexDir = StringUtils.split(this.indexDirs, ",")[0];
+
+        File f = new File(indexDir);
+        Directory directory;
+        try {
+            if (!f.exists()) {
+                f.mkdirs();
+            }
+            directory = FSDirectory.open(f);
+        } catch (IOException e) {
+            LOG.error("Failed to open the index directory: " + e);
+            throw new RuntimeException(e);
+        }
+
+        init(directory, context);
+    }
+
+    public void init(Directory directory, XWikiContext context)
+    {
+
+        int indexingInterval;
+        try {
+            indexingInterval =
+                    1000 * Integer.parseInt(this.config.getProperty(LucenePlugin.PROP_INDEXING_INTERVAL, "30"));
+        } catch (NumberFormatException e) {
+            LOG.warn("Invalid indexing interval in configuration.");
+            indexingInterval = 30000;
+        }
+        int maxQueueSize;
+        try {
+            maxQueueSize = Integer.parseInt(this.config.getProperty(LucenePlugin.PROP_MAX_QUEUE_SIZE, "1000"));
+        } catch (NumberFormatException e) {
+            LOG.warn("Invalid max queue size in configuration.");
+            maxQueueSize = 1000;
+        }
+
+        IndexUpdater indexUpdater = new IndexUpdater(directory, indexingInterval, maxQueueSize, this, context);
+
+        init(indexUpdater, context);
+    }
+
+    public void init(IndexUpdater indexUpdater, XWikiContext context)
+    {
+        Directory directory = indexUpdater.getDirectory();
+
+        boolean needInitialRebuild = true;
+        try {
+            needInitialRebuild = !IndexReader.indexExists(directory);
+        } catch (IOException e) {
+            LOG.warn("Failed to check if index exists: " + e);
+        }
+        IndexRebuilder indexRebuilder = new IndexRebuilder(indexUpdater, context, needInitialRebuild);
+
+        init(indexUpdater, indexRebuilder, context);
+    }
+
+    public void init(IndexUpdater indexUpdater, IndexRebuilder indexRebuilder, XWikiContext context)
+    {
+        super.init(context);
+
+        this.config = context.getWiki().getConfig();
         try {
-            analyzer =
-                (Analyzer) Class.forName(config.getProperty(PROP_ANALYZER, DEFAULT_ANALYZER))
-                    .newInstance();
+            this.analyzer =
+                    (Analyzer) Class.forName(this.config.getProperty(PROP_ANALYZER, DEFAULT_ANALYZER)).newInstance();
         } catch (Exception e) {
             LOG.error("error instantiating analyzer : ", e);
             LOG.warn("using default analyzer class: " + DEFAULT_ANALYZER);
             try {
-                analyzer = (Analyzer) Class.forName(DEFAULT_ANALYZER).newInstance();
+                this.analyzer = (Analyzer) Class.forName(DEFAULT_ANALYZER).newInstance();
             } catch (Exception e1) {
-                throw new RuntimeException("instantiation of default analyzer "
-                    + DEFAULT_ANALYZER + " failed", e1);
+                throw new RuntimeException("instantiation of default analyzer " + DEFAULT_ANALYZER + " failed", e1);
             }
         }
-        this.indexDirs = config.getProperty(PROP_INDEX_DIR);
-        if (indexDirs == null || indexDirs.equals("")) {
+
+        this.indexDirs = this.config.getProperty(PROP_INDEX_DIR);
+        if (StringUtils.isEmpty(this.indexDirs)) {
             File workDir = context.getWiki().getWorkSubdirectory("lucene", context);
-            indexDirs = workDir.getAbsolutePath();
+            this.indexDirs = workDir.getAbsolutePath();
         }
-        indexUpdater = new IndexUpdater();
-        indexUpdater.setAnalyzer(analyzer);
-        indexUpdater.init(config, this, context);
-        indexUpdaterThread = new Thread(indexUpdater, "Lucene Index Updater");
-        indexUpdaterThread.start();
-        indexRebuilder = new IndexRebuilder(indexUpdater, context);
+        String indexDir = StringUtils.split(this.indexDirs, ",")[0];
 
-        openSearchers();
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Assigning index updater: " + indexUpdater);
+        }
+
+        this.indexUpdater = indexUpdater;
+        this.indexUpdater.setAnalyzer(this.analyzer);
+        this.indexUpdaterThread = new Thread(indexUpdater, "Lucene Index Updater");
+        this.indexUpdaterThread.start();
+        this.indexRebuilder = indexRebuilder;
+
+        openSearchers(context);
 
         Utils.getComponent(ObservationManager.class).addListener(indexUpdater);
 
@@ -507,15 +551,15 @@
 
     public void flushCache(XWikiContext context)
     {
-        Utils.getComponent(ObservationManager.class).removeListener(indexUpdater.getName());
+        Utils.getComponent(ObservationManager.class).removeListener(this.indexUpdater.getName());
 
-        indexRebuilder = null;
+        this.indexRebuilder = null;
 
         try {
             // set the thread to exit
-            indexUpdater.doExit();
+            this.indexUpdater.doExit();
             // wait for the thread to finish
-            indexUpdaterThread.join();
+            this.indexUpdaterThread.join();
         } catch (InterruptedException ex) {
             LOG.warn("Error while waiting for indexUpdaterThread to die.", ex);
         }
@@ -526,8 +570,8 @@
             LOG.warn("cannot close searchers", e);
         }
 
-        indexUpdater = null;
-        analyzer = null;
+        this.indexUpdater = null;
+        this.analyzer = null;
 
         init(context);
     }
@@ -548,21 +592,29 @@
      * @param indexDirs Comma separated list of Lucene index directories to create searchers for.
      * @return Array of searchers
      */
-    public Searcher[] createSearchers(String indexDirs) throws Exception
+    public Searcher[] createSearchers(String indexDirs, XWikiContext context) throws Exception
     {
         String[] dirs = StringUtils.split(indexDirs, ",");
         List<IndexSearcher> searchersList = new ArrayList<IndexSearcher>();
         for (int i = 0; i < dirs.length; i++) {
-            try {
-                if (!IndexReader.indexExists(dirs[i])) {
-                    // If there's no index there, create an empty one; otherwise the reader
-                    // constructor will throw an exception and fail to initialize
-                    new IndexWriter(dirs[i], analyzer).close();
+            RETRY: while (true) {
+                try {
+                    try {
+                        if (!IndexReader.indexExists(dirs[i])) {
+                            // If there's no index there, create an empty one; otherwise the reader
+                            // constructor will throw an exception and fail to initialize
+                            new IndexWriter(dirs[i], analyzer).close();
+                        }
+                        IndexReader reader = IndexReader.open(dirs[i], true);
+                        searchersList.add(new IndexSearcher(reader));
+                        break RETRY;
+                    } catch (CorruptIndexException e) {
+                        handleCorruptIndex(context);
+                    }
+                } catch (IOException e) {
+                    LOG.error("cannot open index " + dirs[i], e);
+                    throw new RuntimeException(e);
                 }
-                IndexReader reader = IndexReader.open(dirs[i]);
-                searchersList.add(new IndexSearcher(reader));
-            } catch (IOException e) {
-                LOG.error("cannot open index " + dirs[i], e);
             }
         }
 
@@ -572,16 +624,15 @@
     /**
      * Opens the searchers for the configured index Dirs after closing any already existing ones.
      */
-    protected synchronized void openSearchers()
+    protected synchronized void openSearchers(XWikiContext context)
     {
         try {
             closeSearchers(this.searchers);
-            this.searchers = createSearchers(indexDirs);
+            this.searchers = createSearchers(this.indexDirs, context);
         } catch (Exception e1) {
-            LOG.error("error opening searchers for index dirs "
-                + config.getProperty(PROP_INDEX_DIR), e1);
-            throw new RuntimeException("error opening searchers for index dirs "
-                + config.getProperty(PROP_INDEX_DIR), e1);
+            LOG.error("error opening searchers for index dirs " + config.getProperty(PROP_INDEX_DIR), e1);
+            throw new RuntimeException("error opening searchers for index dirs " + config.getProperty(PROP_INDEX_DIR),
+                e1);
         }
     }
 
@@ -601,27 +652,27 @@
 
     public String getIndexDirs()
     {
-        return indexDirs;
+        return this.indexDirs;
     }
 
     public long getQueueSize()
     {
-        return indexUpdater.getQueueSize();
+        return this.indexUpdater.getQueueSize();
     }
 
     public void queueDocument(XWikiDocument doc, XWikiContext context)
     {
-        indexUpdater.add(doc, context);
+        this.indexUpdater.add(doc, context);
     }
 
     public void queueAttachment(XWikiDocument doc, XWikiAttachment attach, XWikiContext context)
     {
-        indexUpdater.add(doc, attach, context);
+        this.indexUpdater.add(doc, attach, context);
     }
 
     public void queueAttachment(XWikiDocument doc, XWikiContext context)
     {
-        indexUpdater.addAttachmentsOfDocument(doc, context);
+        this.indexUpdater.addAttachmentsOfDocument(doc, context);
     }
 
     /**
@@ -629,14 +680,22 @@
      */
     public long getLuceneDocCount()
     {
-        return indexUpdater.getLuceneDocCount();
+        return this.indexUpdater.getLuceneDocCount();
     }
 
     /**
      * @return the number of documents in the second queue gave to Lucene.
      */
-    public long getActiveQueueSize()
+    // public long getActiveQueueSize()
+    // {
+    // return indexUpdater.getActiveQueueSize();
+    // }
+
+    /**
+     * Handle a corrupt index by clearing it and rebuilding from scratch.
+     */
+    void handleCorruptIndex(XWikiContext context) throws IOException
     {
-        return indexUpdater.getActiveQueueSize();
+        rebuildIndex(context);
     }
 }
Index: src/main/java/com/xpn/xwiki/plugin/lucene/IndexUpdater.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/IndexUpdater.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/IndexUpdater.java	(working copy)
@@ -19,28 +19,23 @@
  */
 package com.xpn.xwiki.plugin.lucene;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.util.Random;
 
-import org.apache.commons.io.IOExceptionWithCause;
-import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.log4j.MDC;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.document.Field;
-import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.CorruptIndexException;
 import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.search.Hits;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.LockObtainFailedException;
 import org.xwiki.observation.EventListener;
 import org.xwiki.observation.event.ActionExecutionEvent;
 import org.xwiki.observation.event.DocumentDeleteEvent;
@@ -77,7 +72,7 @@
     };
 
     /** Milliseconds of sleep between checks for changed documents. */
-    private int indexingInterval = 30000;
+    private final int indexingInterval;
 
     /** Milliseconds left till the next check for changed documents. */
     private int indexingTimer = 0;
@@ -88,11 +83,9 @@
      */
     private volatile boolean exit = false;
 
-    private IndexWriter writer;
-
-    private String indexDir;
+    private final Directory directory;
 
-    private XWikiDocumentQueue queue = new XWikiDocumentQueue();
+    private final XWikiDocumentQueue queue = new XWikiDocumentQueue();
 
     /**
      * Soft threshold after which no more documents will be added to the indexing queue. When the queue size gets larger
@@ -100,25 +93,29 @@
      * milliseconds until the queue size will get back bellow this threshold. This does not affect normal indexing
      * through wiki updates.
      */
-    public int maxQueueSize = 1000;
+    private final int maxQueueSize;
 
     private Analyzer analyzer;
 
-    private LucenePlugin plugin;
-
-    private IndexSearcher searcher;
-
-    private IndexReader reader;
+    private final LucenePlugin plugin;
 
     private XWikiContext context;
 
     private XWiki xwiki;
 
-    private long activesIndexedDocs = 0;
-
     static List<String> fields = new ArrayList<String>();
 
-    public boolean needInitialBuild = false;
+    IndexUpdater(Directory directory, int indexingInterval, int maxQueueSize, LucenePlugin plugin, XWikiContext context)
+    {
+        this.xwiki = context.getWiki();
+        this.context = (XWikiContext) context.clone();
+        this.context.setDatabase(this.context.getMainXWiki());
+        this.plugin = plugin;
+        this.directory = directory;
+
+        this.indexingInterval = indexingInterval;
+        this.maxQueueSize = maxQueueSize;
+    }
 
     public void doExit()
     {
@@ -126,6 +123,15 @@
     }
 
     /**
+     * Return a reference to the directory that this updater is currently working with.
+     */
+
+    public Directory getDirectory()
+    {
+        return directory;
+    }
+
+    /**
      * Main loop. Polls the queue for documents to be indexed.
      * 
      * @see java.lang.Runnable#run()
@@ -184,89 +190,47 @@
                 LOG.debug("IndexUpdater: documents in queue, start indexing");
             }
 
-            Map<String, IndexData> toIndex = new HashMap<String, IndexData>();
-            List<Integer> toDelete = new ArrayList<Integer>();
-            activesIndexedDocs = 0;
-
-            try {
-                openSearcher();
-                while (!this.queue.isEmpty()) {
-                    IndexData data = this.queue.remove();
-                    List<Integer> oldDocs = getOldIndexDocIds(data);
-                    if (oldDocs != null) {
-                        for (Integer id : oldDocs) {
-                            if (LOG.isDebugEnabled()) {
-                                LOG.debug("Adding " + id + " to remove list");
-                            }
+            XWikiContext context = (XWikiContext) this.context.clone();
+            context.getWiki().getStore().cleanUp(context);
 
-                            if (!toDelete.contains(id)) {
-                                toDelete.add(id);
-                            } else {
-                                if (LOG.isDebugEnabled()) {
-                                    LOG.debug("Found " + id + " already in list while adding it to remove list");
-                                }
-                            }
-                        }
-                    }
-
-                    String id = data.getId();
-                    LOG.debug("Adding " + id + " to index list");
-                    if (toIndex.containsKey(id)) {
-                        if (LOG.isDebugEnabled()) {
-                            LOG.debug("Found " + id + " already in list while adding it to index list");
-                        }
-                        toIndex.remove(id);
+            IndexSearcher searcher;
+            IndexWriter writer;
+            RETRY: while (true) {
+                // We will retry after repairing if the index was
+                // corrupt
+                try {
+                    try {
+                        searcher = new IndexSearcher(directory, true);
+                        writer = openWriter(false);
+                        break RETRY;
+                    } catch (CorruptIndexException e) {
+                        plugin.handleCorruptIndex(context);
                     }
-                    ++activesIndexedDocs;
-                    toIndex.put(id, data);
-                }
-            } catch (Exception e) {
-                LOG.error("error preparing index queue", e);
-            } finally {
-                closeSearcher();
-            }
-
-            // Let's delete
-            try {
-                openSearcher();
-                if (LOG.isInfoEnabled()) {
-                    LOG.info("deleting " + toDelete.size() + " docs from lucene index");
-                }
-                int nb = deleteOldDocs(toDelete);
-                if (LOG.isInfoEnabled()) {
-                    LOG.info("deleted " + nb + " docs from lucene index");
+                } catch (IOException e) {
+                    LOG.error("Failed to open index");
+                    throw new RuntimeException(e);
                 }
-            } catch (Exception e) {
-                LOG.error("error deleting previous documents", e);
-            } finally {
-                closeSearcher();
             }
 
-            // Let's index
             try {
-                if (LOG.isInfoEnabled()) {
-                    LOG.info("indexing " + toIndex.size() + " docs to lucene index");
-                }
-
-                XWikiContext context = (XWikiContext) this.context.clone();
-                context.getWiki().getStore().cleanUp(context);
-                openWriter(false);
-
                 int nb = 0;
-                for (Map.Entry<String, IndexData> entry : toIndex.entrySet()) {
-                    String id = entry.getKey();
-                    IndexData data = entry.getValue();
+                while (!this.queue.isEmpty()) {
+                    IndexData data = this.queue.remove();
+
+                    String id = data.getId();
 
                     try {
+                        /*
+                         * XXX Is it not possible to obtain the right translation directly?
+                         */
                         XWikiDocument doc = this.xwiki.getDocument(data.getFullName(), context);
 
                         if (data.getLanguage() != null && !data.getLanguage().equals("")) {
                             doc = doc.getTranslatedDocument(data.getLanguage(), context);
                         }
 
-                        addToIndex(data, doc, context);
+                        addToIndex(writer, searcher, data, doc, context);
                         ++nb;
-                        --activesIndexedDocs;
                     } catch (Exception e) {
                         LOG.error("error indexing document " + id, e);
                     }
@@ -276,136 +240,49 @@
                     LOG.info("indexed " + nb + " docs to lucene index");
                 }
 
-                writer.flush();
+                writer.commit();
             } catch (Exception e) {
                 LOG.error("error indexing documents", e);
             } finally {
                 this.context.getWiki().getStore().cleanUp(this.context);
-                closeWriter();
-            }
-
-            plugin.openSearchers();
-        }
-    }
-
-    private synchronized void closeSearcher()
-    {
-        try {
-            if (this.searcher != null) {
-                this.searcher.close();
-            }
-            if (this.reader != null) {
-                this.reader.close();
+                try {
+                    searcher.close();
+                } catch (IOException e) {
+                    LOG.warn("Failed to close searcher.");
+                }
+                try {
+                    writer.optimize();
+                    writer.close();
+                } catch (IOException e) {
+                    LOG.warn("Failed to close writer.");
+                }
             }
-        } catch (IOException e) {
-            LOG.error("error closing index searcher", e);
-        } finally {
-            this.searcher = null;
-            this.reader = null;
-        }
-    }
 
-    /**
-     * Opens the index reader and searcher used for finding and deleting old versions of indexed documents.
-     */
-    private synchronized void openSearcher()
-    {
-        try {
-            this.reader = IndexReader.open(this.indexDir);
-            this.searcher = new IndexSearcher(this.reader);
-        } catch (IOException e) {
-            LOG.error("error opening index searcher", e);
+            this.plugin.openSearchers(context);
         }
     }
 
-    /**
-     * Deletes the documents with the given ids from the index.
-     */
-    private int deleteOldDocs(List<Integer> oldDocs)
+    protected IndexWriter openWriter(boolean create) throws IOException
     {
-        int nb = 0;
-
-        for (Integer id : oldDocs) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("delete doc " + id);
-            }
-
+        while (true) {
             try {
-                this.reader.deleteDocument(id);
-                nb++;
-            } catch (IOException e1) {
-                LOG.error("error deleting doc " + id, e1);
-            }
-        }
-
-        return nb;
-    }
-
-    private List<Integer> getOldIndexDocIds(IndexData data)
-    {
-        List<Integer> retval = new ArrayList<Integer>(3);
-        Query query = data.buildQuery();
-        try {
-            Hits hits = this.searcher.search(query);
-            for (int i = 0; i < hits.length(); i++) {
-                retval.add(new Integer(hits.id(i)));
-            }
-        } catch (Exception e) {
-            LOG.error(String.format("Error looking for old versions of document [%s] with query [%s]", data, query), e);
-        }
+                IndexWriter w = new IndexWriter(directory, analyzer, create, IndexWriter.MaxFieldLength.LIMITED);
+                w.setUseCompoundFile(true);
 
-        return retval;
-    }
-
-    private void openWriter(boolean create) throws IOException
-    {
-        if (writer != null) {
-            LOG.error("Writer already open and createWriter called");
-            return;
-        }
-
-        try {
-            // fix for windows by Daniel Cortes:
-            FSDirectory f = FSDirectory.getDirectory(indexDir);
-            writer = new IndexWriter(f, analyzer, create);
-            // writer = new IndexWriter (indexDir, analyzer, create);
-            writer.setUseCompoundFile(true);
-
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("successfully opened index writer : " + indexDir);
+                return w;
+            } catch (LockObtainFailedException e) {
+                try {
+                    int s = new Random().nextInt(1000);
+                    LOG.debug("failed to acquire lock, retrying in " + s + "ms ...");
+                    Thread.sleep(s);
+                } catch (InterruptedException e0) {
+                }
             }
-        } catch (IOException e) {
-            throw new IOExceptionWithCause("Error opening Lucene Index for writing at " + indexDir, e);
-        }
-    }
-
-    private void closeWriter()
-    {
-        if (this.writer == null) {
-            LOG.error("Writer not open and closeWriter called");
-            return;
-        }
-
-        try {
-            this.writer.optimize();
-        } catch (IOException e1) {
-            LOG.error("Exception caught when optimizing Index", e1);
-        }
-
-        try {
-            this.writer.close();
-        } catch (Exception e) {
-            LOG.error("Exception caught when closing IndexWriter", e);
-        }
-
-        this.writer = null;
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("closed writer.");
         }
     }
 
-    private void addToIndex(IndexData data, XWikiDocument doc, XWikiContext context) throws IOException
+    private void addToIndex(IndexWriter writer, IndexSearcher searcher, IndexData data, XWikiDocument doc,
+        XWikiContext context) throws IOException
     {
         if (LOG.isDebugEnabled()) {
             LOG.debug("addToIndex: " + data);
@@ -423,16 +300,16 @@
             }
         }
 
-        this.writer.addDocument(luceneDoc);
+        writer.updateDocument(new Term(IndexFields.DOCUMENT_ID, data.getId()), luceneDoc);
     }
 
-    /**
-     * @param indexDir The indexDir to set.
-     */
-    public void setIndexDir(String indexDir)
-    {
-        this.indexDir = indexDir;
-    }
+    // /**
+    // * @param indexDir The indexDir to set.
+    // */
+    // public void setIndexDir(String indexDir)
+    // {
+    // this.indexDir = indexDir;
+    // }
 
     /**
      * @param analyzer The analyzer to set.
@@ -442,58 +319,16 @@
         this.analyzer = analyzer;
     }
 
-    public synchronized void init(Properties config, LucenePlugin plugin, XWikiContext context)
-    {
-        this.xwiki = context.getWiki();
-        this.context = (XWikiContext) context.clone();
-        this.context.setDatabase(this.context.getMainXWiki());
-        this.plugin = plugin;
-        // take the first configured index dir as the one for writing
-        // String[] indexDirs =
-        // StringUtils.split(config.getProperty(LucenePlugin.PROP_INDEX_DIR), "
-        // ,");
-        String[] indexDirs = StringUtils.split(plugin.getIndexDirs(), ",");
-        if (indexDirs != null && indexDirs.length > 0) {
-            this.indexDir = indexDirs[0];
-            File f = new File(indexDir);
-            if (!f.isDirectory()) {
-                f.mkdirs();
-                this.needInitialBuild = true;
-            }
-            if (!IndexReader.indexExists(f)) {
-                this.needInitialBuild = true;
-            }
-        }
-
-        this.indexingInterval = 1000 * Integer.parseInt(config.getProperty(LucenePlugin.PROP_INDEXING_INTERVAL, "30"));
-        this.maxQueueSize = Integer.parseInt(config.getProperty(LucenePlugin.PROP_MAX_QUEUE_SIZE, "1000"));
-
-        // Note: There's no need to open the Searcher here (with a call to
-        // openSearcher()) as each task needing it will open it itself.
-    }
-
     public void cleanIndex() throws IOException
     {
         if (LOG.isInfoEnabled()) {
             LOG.info("trying to clear index for rebuilding");
         }
 
-        while (writer != null) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("waiting for existing index writer to close");
-            }
-
-            try {
-                Thread.sleep(1000);
-            } catch (InterruptedException e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-            }
-        }
-
-        synchronized (this) {
-            openWriter(true);
-            closeWriter();
+        try {
+            openWriter(true).close();
+        } catch (IOException e) {
+            LOG.error("Failed to clean index: " + e);
         }
     }
 
@@ -501,14 +336,6 @@
     {
         this.queue.add(new DocumentData(document, context));
 
-        if (document.hasElement(XWikiDocument.HAS_OBJECTS)) {
-            addObject(document, context);
-        }
-    }
-
-    public void addObject(XWikiDocument document, XWikiContext context)
-    {
-        this.queue.add(new ObjectData(document, context));
     }
 
     public void add(XWikiDocument document, XWikiAttachment attachment, XWikiContext context)
@@ -562,7 +389,10 @@
                 // Retrieve the latest version (with the file just attached)
                 XWikiDocument basedoc = context.getWiki().getDocument(document.getFullName(), context);
                 List<XWikiAttachment> attachments = basedoc.getAttachmentList();
-                // find out the most recently changed attachment
+                /*
+                 * XXX Race condition: if two or more attachments are added before we find the "newest attachment"
+                 * below, only the last one added will be indexed.
+                 */
                 XWikiAttachment newestAttachment = null;
                 for (XWikiAttachment attachment : attachments) {
                     if ((newestAttachment == null) || attachment.getDate().after(newestAttachment.getDate())) {
@@ -597,17 +427,19 @@
      */
     public long getLuceneDocCount()
     {
-        if (writer != null)
-            return writer.docCount();
+        try {
+            IndexWriter w = openWriter(false);
+            long n = w.docCount();
+            w.close();
+        } catch (IOException e) {
+        }
 
         return -1;
     }
 
-    /**
-     * @return the number of documents in the second queue gave to Lucene.
-     */
-    public long getActiveQueueSize()
+    public int getMaxQueueSize()
     {
-        return this.activesIndexedDocs;
+        return maxQueueSize;
     }
+
 }
Index: src/main/java/com/xpn/xwiki/plugin/lucene/IndexData.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/IndexData.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/IndexData.java	(working copy)
@@ -21,14 +21,17 @@
 
 import java.util.Date;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
+import org.xwiki.rendering.syntax.Syntax;
 
 import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.XWikiException;
 import com.xpn.xwiki.doc.XWikiDocument;
 
 /**
@@ -42,7 +45,7 @@
 
     private String documentName;
 
-    private String documentWeb;
+    private String documentSpace;
 
     private String documentFullName;
 
@@ -59,102 +62,87 @@
     private Date modificationDate;
 
     /**
-     * name of the virtual wiki this doc belongs to
+     * name of the wiki this doc belongs to
      */
     private String wiki;
 
     public IndexData(final XWikiDocument doc, final XWikiContext context)
     {
         setDocumentName(doc.getName());
-        setDocumentTitle(doc.getDisplayTitle(context));
-        setDocumentWeb(doc.getSpace());
+        try {
+            setDocumentTitle(doc.getRenderedTitle(Syntax.PLAIN_1_0, context));
+        } catch (XWikiException e) {
+            LOG.error("Failed to render document title content", e);
+            setDocumentTitle(doc.getName());
+        }
+        setDocumentSpace(doc.getSpace());
         setDocumentFullName(doc.getFullName());
         setWiki(doc.getDatabase() == null ? context.getDatabase() : doc.getDatabase());
-        setFullName(new StringBuffer(wiki).append(":").append(documentWeb).append(".").append(
-            documentName).toString());
+        setFullName(new StringBuffer(this.wiki).append(":").append(this.documentSpace).append(".").append(
+            this.documentName).toString());
         setLanguage(doc.getLanguage());
     }
 
     /**
-     * Adds this documents data to a lucene Document instance for indexing. <p> <strong>Short introduction to Lucene
-     * field types </strong> </p> <p> Which type of Lucene field is used determines what Lucene does with data and how
-     * we can use it for searching and showing search results: </p> <ul> <li>Keyword fields don't get tokenized, but are
-     * searchable and stored in the index. This is perfect for fields you want to search in programmatically (like ids
-     * and such), and date fields. Since all user-entered queries are tokenized, letting the user search these fields
-     * makes almost no sense, except of queries for date fields, where tokenization is useless.</li> <li>the stored text
-     * fields are used for short texts which should be searchable by the user, and stored in the index for
-     * reconstruction. Perfect for document names, titles, abstracts.</li> <li>the unstored field takes the biggest part
-     * of the content - the full text. It is tokenized and indexed, but not stored in the index. This makes sense, since
-     * when the user wants to see the full content, he clicks the link to vie the full version of a document, which is
-     * then delivered by xwiki.</li> </ul>
-     *
+     * Adds this documents data to a lucene Document instance for indexing.
+     * <p>
+     * <strong>Short introduction to Lucene field types </strong>
+     * </p>
+     * <p>
+     * Which type of Lucene field is used determines what Lucene does with data and how we can use it for searching and
+     * showing search results:
+     * </p>
+     * <ul>
+     * <li>Keyword fields don't get tokenized, but are searchable and stored in the index. This is perfect for fields
+     * you want to search in programmatically (like ids and such), and date fields. Since all user-entered queries are
+     * tokenized, letting the user search these fields makes almost no sense, except of queries for date fields, where
+     * tokenization is useless.</li>
+     * <li>the stored text fields are used for short texts which should be searchable by the user, and stored in the
+     * index for reconstruction. Perfect for document names, titles, abstracts.</li>
+     * <li>the unstored field takes the biggest part of the content - the full text. It is tokenized and indexed, but
+     * not stored in the index. This makes sense, since when the user wants to see the full content, he clicks the link
+     * to vie the full version of a document, which is then delivered by xwiki.</li>
+     * </ul>
+     * 
      * @param luceneDoc if not null, this controls which translated version of the content will be indexed. If null, the
-     * content in the default language will be used.
+     *            content in the default language will be used.
      */
-    public void addDataToLuceneDocument(org.apache.lucene.document.Document luceneDoc,
-        XWikiDocument doc, XWikiContext context)
+    public void addDataToLuceneDocument(org.apache.lucene.document.Document luceneDoc, XWikiDocument doc,
+        XWikiContext context)
     {
         // Keyword fields: stored and indexed, but not tokenized
         // Note: ID field must be UN_TOKENIZED to enable case sensitive IDs
-        luceneDoc.add(new Field(IndexFields.DOCUMENT_ID,
-            getId(),
-            Field.Store.YES,
-            Field.Index.UN_TOKENIZED));
-        luceneDoc.add(new Field(IndexFields.DOCUMENT_LANGUAGE,
-            this.language,
-            Field.Store.YES,
-            Field.Index.TOKENIZED));
-        if (wiki != null && wiki.length() > 0) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_WIKI,
-                wiki,
-                Field.Store.YES,
-                Field.Index.TOKENIZED));
+        luceneDoc.add(new Field(IndexFields.DOCUMENT_ID, getId(), Field.Store.YES, Field.Index.NOT_ANALYZED));
+        luceneDoc.add(new Field(IndexFields.DOCUMENT_LANGUAGE, this.language, Field.Store.YES, Field.Index.ANALYZED));
+        if (!StringUtils.isEmpty(this.wiki)) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_WIKI, this.wiki, Field.Store.YES, Field.Index.ANALYZED));
         }
         if (getType() != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_TYPE,
-                getType(),
-                Field.Store.YES,
-                Field.Index.TOKENIZED));
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_TYPE, getType(), Field.Store.YES, Field.Index.ANALYZED));
         }
-        if (modificationDate != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_DATE, IndexFields
-                .dateToString(modificationDate), Field.Store.YES, Field.Index.UN_TOKENIZED));
+        if (this.modificationDate != null) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_DATE, IndexFields.dateToString(this.modificationDate),
+                Field.Store.YES, Field.Index.NOT_ANALYZED));
         }
-        if (creationDate != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_CREATIONDATE, IndexFields
-                .dateToString(creationDate), Field.Store.YES, Field.Index.UN_TOKENIZED));
+        if (this.creationDate != null) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_CREATIONDATE, IndexFields.dateToString(this.creationDate),
+                Field.Store.YES, Field.Index.NOT_ANALYZED));
         }
 
         // stored Text fields: tokenized and indexed
-        if (documentTitle != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_TITLE,
-                documentTitle,
-                Field.Store.YES,
-                Field.Index.TOKENIZED));
+        if (this.documentTitle != null) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_TITLE, this.documentTitle, Field.Store.YES,
+                Field.Index.ANALYZED));
         }
-        luceneDoc.add(new Field(IndexFields.DOCUMENT_NAME,
-            documentName,
-            Field.Store.YES,
-            Field.Index.TOKENIZED));
-        luceneDoc.add(new Field(IndexFields.DOCUMENT_WEB,
-            documentWeb,
-            Field.Store.YES,
-            Field.Index.TOKENIZED));
-        luceneDoc.add(new Field(IndexFields.DOCUMENT_FULLNAME,
-            documentFullName,
-            Field.Store.YES,
-            Field.Index.TOKENIZED));
-        if (author != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_AUTHOR,
-                author,
-                Field.Store.YES,
-                Field.Index.TOKENIZED));
+        luceneDoc.add(new Field(IndexFields.DOCUMENT_NAME, this.documentName, Field.Store.YES, Field.Index.ANALYZED));
+        luceneDoc.add(new Field(IndexFields.DOCUMENT_WEB, this.documentSpace, Field.Store.YES, Field.Index.ANALYZED));
+        luceneDoc.add(new Field(IndexFields.DOCUMENT_FULLNAME, this.documentFullName, Field.Store.YES,
+            Field.Index.ANALYZED));
+        if (this.author != null) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_AUTHOR, this.author, Field.Store.YES, Field.Index.ANALYZED));
         }
-        if (creator != null) {
-            luceneDoc.add(new Field(IndexFields.DOCUMENT_CREATOR,
-                creator,
-                Field.Store.YES,
-                Field.Index.TOKENIZED));
+        if (this.creator != null) {
+            luceneDoc.add(new Field(IndexFields.DOCUMENT_CREATOR, this.creator, Field.Store.YES, Field.Index.ANALYZED));
         }
 
         // UnStored fields: tokenized and indexed, but no reconstruction of
@@ -162,20 +150,17 @@
         try {
             final String ft = getFullText(doc, context);
             if (ft != null) {
-                luceneDoc.add(new Field(IndexFields.FULLTEXT,
-                    ft,
-                    Field.Store.NO,
-                    Field.Index.TOKENIZED));
+                luceneDoc.add(new Field(IndexFields.FULLTEXT, ft, Field.Store.NO, Field.Index.ANALYZED));
             }
         } catch (Exception e) {
-            LOG.error("error extracting fulltext for document " + this, e);
+            LOG.error("Error extracting fulltext for document [" + this + "]", e);
         }
     }
 
     /**
      * Builds a Lucene query matching only the document this instance represents. This is used for removing old versions
      * of a document from the index before adding a new one.
-     *
+     * 
      * @return a query matching the field DOCUMENT_ID to the value of #getId()
      */
     public Query buildQuery()
@@ -189,12 +174,14 @@
     public String getId()
     {
         StringBuffer retval = new StringBuffer();
-        if (wiki != null && wiki.length() > 0) {
-            retval.append(wiki).append(":");
+
+        if (!StringUtils.isEmpty(this.wiki)) {
+            retval.append(this.wiki).append(":");
         }
-        retval.append(documentWeb).append(".");
-        retval.append(documentName).append(".");
-        retval.append(language);
+        retval.append(this.documentSpace).append(".");
+        retval.append(this.documentName).append(".");
+        retval.append(this.language);
+
         return retval.toString();
     }
 
@@ -203,12 +190,19 @@
      */
     public String getFullText(XWikiDocument doc, XWikiContext context)
     {
-        StringBuffer sb =
-            new StringBuffer(documentName).append(" ").append(documentWeb).append(" ").append(
-                author).append(creator);
+        StringBuilder sb = new StringBuilder();
+
+        getFullText(sb, doc, context);
+
         return sb.toString();
     }
 
+    protected void getFullText(StringBuilder sb, XWikiDocument doc, XWikiContext context)
+    {
+        sb.append(this.documentName).append(" ").append(this.documentSpace).append(" ").append(this.author).append(" ").append(
+            this.creator);
+    }
+
     public abstract String getType();
 
     public String toString()
@@ -242,10 +236,17 @@
 
     /**
      * @param documentWeb The documentWeb to set.
+     * @deprecated use {@link #setDocumentSpace(String)} instead
      */
+    @Deprecated
     public void setDocumentWeb(String documentWeb)
     {
-        this.documentWeb = documentWeb;
+        setDocumentSpace(documentWeb);
+    }
+
+    public void setDocumentSpace(String documentSpace)
+    {
+        this.documentSpace = documentSpace;
     }
 
     /**
@@ -266,27 +267,36 @@
 
     public String getDocumentTitle()
     {
-        return documentTitle;
+        return this.documentTitle;
     }
 
     public String getDocumentName()
     {
-        return documentName;
+        return this.documentName;
     }
 
+    /**
+     * @deprecated use {@link #getDocumentSpace()} instead
+     */
+    @Deprecated
     public String getDocumentWeb()
     {
-        return documentWeb;
+        return getDocumentSpace();
+    }
+
+    public String getDocumentSpace()
+    {
+        return this.documentSpace;
     }
 
     public String getDocumentFullName()
     {
-        return documentFullName;
+        return this.documentFullName;
     }
 
     public String getWiki()
     {
-        return wiki;
+        return this.wiki;
     }
 
     public void setWiki(String wiki)
@@ -296,7 +306,7 @@
 
     public Date getCreationDate()
     {
-        return creationDate;
+        return this.creationDate;
     }
 
     public void setCreationDate(Date creationDate)
@@ -306,7 +316,7 @@
 
     public String getCreator()
     {
-        return creator;
+        return this.creator;
     }
 
     public void setCreator(String creator)
@@ -316,7 +326,7 @@
 
     public String getFullName()
     {
-        return fullName;
+        return this.fullName;
     }
 
     public void setFullName(String fullName)
@@ -326,12 +336,12 @@
 
     public String getLanguage()
     {
-        return language;
+        return this.language;
     }
 
     public void setLanguage(String lang)
     {
-        if (lang != null && lang.length() > 0) {
+        if (!StringUtils.isEmpty(lang)) {
             this.language = lang;
         } else {
             this.language = "default";
Index: src/main/java/com/xpn/xwiki/plugin/lucene/DocumentData.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/DocumentData.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/DocumentData.java	(working copy)
@@ -21,15 +21,32 @@
 
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.doc.XWikiDocument;
+import com.xpn.xwiki.objects.BaseObject;
+import com.xpn.xwiki.objects.classes.BaseClass;
+import com.xpn.xwiki.objects.BaseProperty;
+import com.xpn.xwiki.objects.classes.StaticListClass;
+import com.xpn.xwiki.objects.PropertyInterface;
+import com.xpn.xwiki.objects.classes.PasswordClass;
+import com.xpn.xwiki.objects.classes.ListItem;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+import java.util.Map;
+import java.util.List;
 
 /**
- * Holds all data but the content of a wiki page to be indexed. The content is retrieved at indexing
- * time, which should save us some memory especially when rebuilding an index for a big wiki.
+ * Holds all data but the content of a wiki page to be indexed. The content is retrieved at indexing time, which should
+ * save us some memory especially when rebuilding an index for a big wiki.
  * 
  * @version $Id$
  */
 public class DocumentData extends IndexData
 {
+    private static final Log LOG = LogFactory.getLog(DocumentData.class);
+
     public DocumentData(final XWikiDocument doc, final XWikiContext context)
     {
         super(doc, context);
@@ -49,17 +66,132 @@
     }
 
     /**
-     * @return a string containing the result of {@link IndexData#getFullText} plus the full text
-     *         content of this document (in the given language)
+     * @return a string containing the result of {@link IndexData#getFullText} plus the full text content of this
+     *         document (in the given language)
      */
-    public String getFullText(XWikiDocument doc, XWikiContext context)
+    protected void getFullText(StringBuilder sb, XWikiDocument doc, XWikiContext context)
+    {
+        super.getFullText(sb, doc, context);
+
+        sb.append(" ");
+        sb.append(getDocumentTitle());
+        sb.append(" ");
+        sb.append(doc.getContent());
+        sb.append(" ");
+
+        getObjectFullText(sb, doc, context);
+    }
+
+    /**
+     * Add to the string builder, the result of {@link IndexData#getFullText(XWikiDocument,XWikiContext)}plus the full
+     * text content (values of title,category,content and extract ) XWiki.ArticleClass Object, as far as it could be
+     * extracted.
+     */
+    private void getObjectFullText(StringBuilder sb, XWikiDocument doc, XWikiContext context)
+    {
+        super.getFullText(sb, doc, context);
+        getObjectContentAsText(sb, doc, context);
+    }
+
+    /**
+     * Add to the string builder the value of title,category,content and extract of XWiki.ArticleClass
+     */
+    private void getObjectContentAsText(StringBuilder sb, XWikiDocument doc, XWikiContext context)
+    {
+        LOG.info(doc.getFullName());
+
+        for (String className : doc.getxWikiObjects().keySet()) {
+            for (BaseObject obj : doc.getObjects(className)) {
+                extractObjectContent(sb, obj, context);
+            }
+        }
+    }
+
+    private void getObjectContentAsText(StringBuilder contentText, BaseObject baseObject, String property,
+        XWikiContext context)
     {
-        StringBuffer text = new StringBuffer(super.getFullText(doc, context));
-        text.append(" ");
-        text.append(super.getDocumentTitle());
-        text.append(" ");
-        text.append(doc.getContent());
+        BaseProperty baseProperty;
+        baseProperty = (BaseProperty) baseObject.getField(property);
+        // XXX Can baseProperty really be null?
+        if (baseProperty != null && baseProperty.getValue() != null) {
+            PropertyInterface prop = baseObject.getxWikiClass(context).getField(property);
+            if (!(prop instanceof PasswordClass)) {
+                contentText.append(baseProperty.getValue().toString());
+            }
+        }
+    }
 
-        return text.toString();
+    private void extractObjectContent(StringBuilder contentText, BaseObject baseObject, XWikiContext context)
+    {
+        if (baseObject != null) {
+            String[] propertyNames = baseObject.getPropertyNames();
+            for (String propertyName : propertyNames) {
+                getObjectContentAsText(contentText, baseObject, propertyName, context);
+                contentText.append(" ");
+            }
+        }
     }
+
+    @Override
+    public void addDataToLuceneDocument(org.apache.lucene.document.Document luceneDoc, XWikiDocument doc,
+        XWikiContext context)
+    {
+        super.addDataToLuceneDocument(luceneDoc, doc, context);
+        for (String className : doc.getxWikiObjects().keySet()) {
+            for (BaseObject obj : doc.getObjects(className)) {
+                if (obj != null) {
+                    luceneDoc.add(new Field(IndexFields.OBJECT, obj.getClassName(), Field.Store.YES,
+                        Field.Index.ANALYZED));
+                    Object[] propertyNames = obj.getPropertyNames();
+                    for (int i = 0; i < propertyNames.length; i++) {
+                        indexProperty(luceneDoc, obj, (String) propertyNames[i], context);
+                    }
+                }
+            }
+        }
+    }
+
+    private void indexProperty(Document luceneDoc, BaseObject baseObject,
+        String propertyName, XWikiContext context)
+    {
+        String fieldFullName = baseObject.getClassName() + "." + propertyName;
+        BaseClass bClass = baseObject.getxWikiClass(context);
+        PropertyInterface prop = bClass.getField(propertyName);
+
+        if (prop instanceof PasswordClass) {
+            // Do not index passwords
+        } else if (prop instanceof StaticListClass && ((StaticListClass) prop).isMultiSelect()) {
+            indexStaticList(luceneDoc, baseObject, (StaticListClass) prop, propertyName, context);
+        } else {
+            StringBuilder sb = new StringBuilder();
+            getObjectContentAsText(sb, baseObject, propertyName, context);
+            luceneDoc.add(new Field(fieldFullName, sb.toString(), Field.Store.YES, Field.Index.ANALYZED));
+        }
+    }
+
+    private void indexStaticList(Document luceneDoc, BaseObject baseObject,
+        StaticListClass prop, String propertyName, XWikiContext context)
+    {
+        Map<String, ListItem> possibleValues = prop.getMap(context);
+        String fieldFullName = baseObject.getClassName() + "." + propertyName;
+
+        for (String value : (List<String>) baseObject.getListValue(propertyName)) {
+            ListItem item = possibleValues.get(value);
+            if (item != null) {
+                // we index the key of the list
+                String fieldName = fieldFullName + ".key";
+                luceneDoc.add(new Field(fieldName, item.getId(), Field.Store.YES, Field.Index.ANALYZED));
+                // we index the value
+                fieldName = fieldFullName + ".value";
+                luceneDoc.add(new Field(fieldName, item.getValue(), Field.Store.YES, Field.Index.ANALYZED));
+                if (!item.getId().equals(item.getValue())) {
+                    luceneDoc.add(new Field(fieldFullName, item.getValue(), Field.Store.YES, Field.Index.ANALYZED));
+                }
+            }
+
+            // we index both if value is not equal to the id(key)
+            luceneDoc.add(new Field(fieldFullName, value, Field.Store.YES, Field.Index.ANALYZED));
+        }
+    }
+
 }
Index: src/main/java/com/xpn/xwiki/plugin/lucene/LucenePluginApi.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/LucenePluginApi.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/LucenePluginApi.java	(working copy)
@@ -184,14 +184,6 @@
     }
 
     /**
-     * @return the number of documents in the second queue gave to Lucene.
-     */
-    public long getActiveQueueSize()
-    {
-        return getProtectedPlugin().getActiveQueueSize();
-    }
-
-    /**
      * @return the number of documents Lucene index writer.
      */
     public long getLuceneDocCount()
Index: src/main/java/com/xpn/xwiki/plugin/lucene/AttachmentData.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/AttachmentData.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/AttachmentData.java	(working copy)
@@ -78,8 +78,9 @@
     public void addDataToLuceneDocument(Document luceneDoc, XWikiDocument doc, XWikiContext context)
     {
         super.addDataToLuceneDocument(luceneDoc, doc, context);
-        if (filename != null) {
-            luceneDoc.add(new Field(IndexFields.FILENAME, filename, Field.Store.YES, Field.Index.TOKENIZED));
+
+        if (this.filename != null) {
+            luceneDoc.add(new Field(IndexFields.FILENAME, filename, Field.Store.YES, Field.Index.ANALYZED));
         }
     }
 
@@ -104,7 +105,7 @@
      */
     public String getFilename()
     {
-        return filename;
+        return this.filename;
     }
 
     /**
@@ -122,7 +123,7 @@
      */
     public String getId()
     {
-        return new StringBuffer(super.getId()).append(".file.").append(filename).toString();
+        return new StringBuffer(super.getId()).append(".file.").append(this.filename).toString();
     }
 
     /**
@@ -146,16 +147,16 @@
         String contentText = null;
 
         try {
-            XWikiAttachment att = doc.getAttachment(filename);
+            XWikiAttachment att = doc.getAttachment(this.filename);
 
-            LOG.debug("have attachment for filename " + filename + ": " + att);
+            LOG.debug("have attachment for filename " + this.filename + ": " + att);
 
             byte[] content = att.getContent(context);
-            if (filename != null) {
-                String[] nameParts = filename.split("\\.");
+            if (this.filename != null) {
+                String[] nameParts = this.filename.split("\\.");
                 if (nameParts.length > 1) {
                     contentText =
-                        TextExtractor.getText(content, MIMETYPES.get(nameParts[nameParts.length - 1].toLowerCase()));
+                            TextExtractor.getText(content, MIMETYPES.get(nameParts[nameParts.length - 1].toLowerCase()));
                 }
             }
         } catch (Exception e) {
Index: src/main/java/com/xpn/xwiki/plugin/lucene/SearchResults.java
===================================================================
--- src/main/java/com/xpn/xwiki/plugin/lucene/SearchResults.java	(revision 25374)
+++ src/main/java/com/xpn/xwiki/plugin/lucene/SearchResults.java	(working copy)
@@ -19,21 +19,22 @@
  */
 package com.xpn.xwiki.plugin.lucene;
 
-import com.xpn.xwiki.XWikiContext;
-import com.xpn.xwiki.api.Api;
-import com.xpn.xwiki.api.XWiki;
-import org.apache.lucene.search.Hits;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.search.Hits;
 
-import java.util.ArrayList;
-import java.util.List;
+import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.api.Api;
+import com.xpn.xwiki.api.XWiki;
 
 /**
  * Container for the results of a search.
  * <p>
- * This class handles paging through search results and enforces the xwiki rights management by only
- * returning search results the user executing the search is allowed to view.
+ * This class handles paging through search results and enforces the xwiki rights management by only returning search
+ * results the user executing the search is allowed to view.
  * </p>
  * 
  * @version $Id$
@@ -46,7 +47,7 @@
 
     private static final Log LOG = LogFactory.getLog(SearchResults.class);
 
-    private List relevantResults;
+    private List<SearchResult> relevantResults;
 
     /**
      * @param hits Lucene search results
@@ -60,10 +61,10 @@
         this.xwiki = xwiki;
     }
 
-    private List getRelevantResults()
+    private List<SearchResult> getRelevantResults()
     {
-        if (relevantResults == null) {
-            relevantResults = new ArrayList();
+        if (this.relevantResults == null) {
+            this.relevantResults = new ArrayList<SearchResult>();
             final int hitcount = hits.length();
 
             String database = this.context.getDatabase();
@@ -71,29 +72,28 @@
                 for (int i = 0; i < hitcount; i++) {
                     SearchResult result = null;
                     try {
-                        result = new SearchResult(hits.doc(i), hits.score(i), xwiki);
+                        result = new SearchResult(this.hits.doc(i), this.hits.score(i), this.xwiki);
 
                         this.context.setDatabase(result.getWiki());
 
                         String pageName = null;
                         if (result.isWikiContent()) {
-                            pageName =
-                                result.getWiki() + ":" + result.getWeb() + "." + result.getName();
+                            pageName = result.getWiki() + ":" + result.getWeb() + "." + result.getName();
                         }
-                        if (result != null && result.isWikiContent()
-                            && xwiki.checkAccess(pageName, "view") && xwiki.exists(pageName)) {
+                        if (result != null && result.isWikiContent() && this.xwiki.checkAccess(pageName, "view")
+                            && this.xwiki.exists(pageName)) {
                             relevantResults.add(result);
                         }
                     } catch (Exception e) {
-                        LOG.error("error getting search result", e);
-                        e.printStackTrace();
+                        LOG.error("Error getting search result", e);
                     }
                 }
             } finally {
                 this.context.setDatabase(database);
             }
         }
-        return relevantResults;
+
+        return this.relevantResults;
     }
 
     /**
@@ -103,12 +103,12 @@
     {
         final int itemCount = Integer.parseInt(items);
         final int begin = Integer.parseInt(beginIndex);
+
         return begin + itemCount - 1 < getRelevantResults().size();
     }
 
     /**
-     * @return true when there is a page before the one currently displayed, that is, when
-     *         <code>beginIndex > 1</code>
+     * @return true when there is a page before the one currently displayed, that is, when <code>beginIndex > 1</code>
      */
     public boolean hasPrevious(String beginIndex)
     {
@@ -116,24 +116,26 @@
     }
 
     /**
-     * @return the value to be used for the firstIndex URL parameter to build a link pointing to the
-     *         next page of results
+     * @return the value to be used for the firstIndex URL parameter to build a link pointing to the next page of
+     *         results
      */
     public int getNextIndex(String beginIndex, String items)
     {
         final int itemCount = Integer.parseInt(items);
         final int resultcount = getRelevantResults().size();
         int retval = Integer.parseInt(beginIndex) + itemCount;
+
         return retval > resultcount ? (resultcount - itemCount + 1) : retval;
     }
 
     /**
-     * @return the value to be used for the firstIndex URL parameter to build a link pointing to the
-     *         previous page of results
+     * @return the value to be used for the firstIndex URL parameter to build a link pointing to the previous page of
+     *         results
      */
     public int getPreviousIndex(String beginIndex, String items)
     {
         int retval = Integer.parseInt(beginIndex) - Integer.parseInt(items);
+
         return 0 < retval ? retval : 1;
     }
 
@@ -147,53 +149,53 @@
         if (retval > resultcount) {
             return resultcount;
         }
+
         return retval;
     }
 
     /**
-     * Helper method for use in velocity templates, takes string values instead of ints. See {@link
-     * #getResults(int,int)}.
+     * Helper method for use in velocity templates, takes string values instead of ints. See
+     * {@link #getResults(int,int)}.
      */
-    public List getResults(String beginIndex, String items)
+    public List<SearchResult> getResults(String beginIndex, String items)
     {
         return getResults(Integer.parseInt(beginIndex), Integer.parseInt(items));
     }
 
     /**
-     * Returns a list of search results. According to beginIndex and endIndex, only a subset of the
-     * results is returned. To get the first ten results, one would use beginIndex=1 and items=10.
+     * Returns a list of search results. According to beginIndex and endIndex, only a subset of the results is returned.
+     * To get the first ten results, one would use beginIndex=1 and items=10.
      * 
      * @param beginIndex 1-based index of first result to return.
      * @param items number of items to return
-     * @return List of SearchResult instances starting at <code>beginIndex</code> and containing
-     *         up to <code>items</code> elements.
+     * @return List of SearchResult instances starting at <code>beginIndex</code> and containing up to
+     *         <code>items</code> elements.
      */
-    public List getResults(int beginIndex, int items)
+    public List<SearchResult> getResults(int beginIndex, int items)
     {
         final int listStartIndex = beginIndex - 1;
         final int listEndIndex = listStartIndex + items;
         int resultcount = 0;
-        List relResults = relevantResults;
+        List<SearchResult> relResults = this.relevantResults;
         if (relResults == null) {
-            relResults = new ArrayList();
-            final int hitcount = hits.length();
+            relResults = new ArrayList<SearchResult>();
+            final int hitcount = this.hits.length();
 
             String database = this.context.getDatabase();
             try {
                 for (int i = 0; i < hitcount; i++) {
                     SearchResult result = null;
                     try {
-                        result = new SearchResult(hits.doc(i), hits.score(i), xwiki);
+                        result = new SearchResult(this.hits.doc(i), this.hits.score(i), this.xwiki);
 
                         this.context.setDatabase(result.getWiki());
 
                         String pageName = null;
                         if (result.isWikiContent()) {
-                            pageName =
-                                result.getWiki() + ":" + result.getWeb() + "." + result.getName();
+                            pageName = result.getWiki() + ":" + result.getSpace() + "." + result.getName();
                         }
-                        if (result != null && result.isWikiContent() && xwiki.exists(pageName)
-                            && xwiki.checkAccess(pageName, "view")) {
+                        if (result.isWikiContent() && this.xwiki.exists(pageName)
+                            && this.xwiki.checkAccess(pageName, "view")) {
                             if (resultcount >= listStartIndex) {
                                 relResults.add(result);
                             }
@@ -203,7 +205,6 @@
                         }
                     } catch (Exception e) {
                         LOG.error("error getting search result", e);
-                        e.printStackTrace();
                     }
                 }
             } finally {
@@ -213,15 +214,15 @@
             return relResults;
         } else {
             resultcount = getRelevantResults().size();
-            return getRelevantResults().subList(listStartIndex,
-                listEndIndex < resultcount ? listEndIndex : resultcount);
+
+            return getRelevantResults().subList(listStartIndex, listEndIndex < resultcount ? listEndIndex : resultcount);
         }
     }
 
     /**
      * @return all search results in one list.
      */
-    public List getResults()
+    public List<SearchResult> getResults()
     {
         return getRelevantResults();
     }
@@ -239,7 +240,7 @@
      */
     public int getTotalHitcount()
     {
-        return hits.length();
+        return this.hits.length();
     }
 
 }
