[exo-jcr-commits] exo-jcr SVN: r198 - in jcr/trunk/component/core: src/main/java/org/exoplatform/services/jcr/config and 6 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Oct 2 11:41:15 EDT 2009


Author: skabashnyuk
Date: 2009-10-02 11:41:14 -0400 (Fri, 02 Oct 2009)
New Revision: 198

Added:
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexException.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/RepositoryIndexSearcherHolder.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneVirtualTableResolver.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeTypeVirtualTableResolver.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/VirtualTableResolver.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.1.dtd
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.2.dtd
Modified:
   jcr/trunk/component/core/pom.xml
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerEntryWrapper.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/core/nodetype/NodeTypeDataManager.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/NamespaceRegistryImpl.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/NodeTypeDataManagerImpl.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/VolatileNodeTypeDataManager.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/ErrorLog.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationEntityResolver.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationImpl.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/QueryImpl.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
   jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.0.dtd
Log:
EXOJCR-161 : indexer configuration update

Modified: jcr/trunk/component/core/pom.xml
===================================================================
--- jcr/trunk/component/core/pom.xml	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/pom.xml	2009-10-02 15:41:14 UTC (rev 198)
@@ -112,6 +112,12 @@
       <dependency>
          <groupId>commons-dbcp</groupId>
          <artifactId>commons-dbcp</artifactId>
+         <exclusions>
+                    <exclusion>
+                        <groupId>xerces</groupId>
+                        <artifactId>xercesImpl</artifactId>
+                    </exclusion>
+         </exclusions>
       </dependency>
 
       <!-- JOTM comes from exo.kernel.component.common -->
@@ -129,7 +135,8 @@
                <artifactId>log4j</artifactId>
             </exclusion>
          </exclusions>
-      </dependency -->
+      </dependency
+-->
 
       <dependency>
          <groupId>javax.resource</groupId>
@@ -205,7 +212,8 @@
          <artifactId>mysql-connector-java</artifactId>
          <version>5.0.5</version>
          <scope>test</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For PostgresSQL support -->
       <!-- dependency>
@@ -213,7 +221,8 @@
          <artifactId>postgresql</artifactId>
          <version>8.2-504.jdbc3</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For Oracle 10g support (local-jcr repository) -->
       <!-- dependency>
@@ -227,7 +236,8 @@
          <artifactId>orai18n</artifactId>
          <version>14</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For IBM DB2 support (local-jcr repository) -->
       <!-- dependency>
@@ -241,7 +251,8 @@
          <artifactId>db2jcc_license_cu</artifactId>
          <version>9.1</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For MS SQL 7/2000/2005 and Sybase ASE/Anywhere support (jTDS driver) -->
       <!-- dependency>
@@ -249,7 +260,8 @@
          <artifactId>jtds</artifactId>
          <version>1.2</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For MS SQL 2005 support (Microsoft JDBC driver) (local-jcr repository) -->
       <!-- dependency>
@@ -257,7 +269,8 @@
          <artifactId>sqljdbc</artifactId>
          <version>9.0</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For Sybase ASE/Anywhere support (jConnect driver) (local-jcr repository) -->
       <!-- dependency>
@@ -265,7 +278,8 @@
          <artifactId>jconn3</artifactId>
          <version>6.05</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- For Apache Derby support (aka JavaDB) -->
       <!-- dependency>
@@ -273,7 +287,8 @@
          <artifactId>derby</artifactId>
          <version>10.2.2.0</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- Ingres Database (local repository) -->
       <!-- dependency>
@@ -281,7 +296,8 @@
          <artifactId>iijdbc</artifactId>
          <version>9.2</version>
          <scope>test</scope>
-      </dependency -->
+      </dependency
+-->
 
       <!-- H2 Database -->
       <!--dependency>
@@ -289,7 +305,8 @@
          <artifactId>h2</artifactId>
          <version>1.0.74</version>
          <scope>compile</scope>
-      </dependency -->
+      </dependency
+-->
       <!-- ======================================================================= -->
    </dependencies>
 
@@ -428,8 +445,14 @@
                   <exclude>**/TestAggregateRules.java</exclude>
                   <exclude>**/IndexingAggregateTest.java</exclude>
                   <exclude>**/IndexingRuleTest.java</exclude>
+                  <exclude>**/TestExcelFileSearch.java</exclude>
+                  <exclude>**/TestRewriteNode.java</exclude>
+                  <exclude>**/TestArabicSearch.java</exclude>
+                  <exclude>**/TestDateSearch.java</exclude>
+                  <exclude>**/TestBinarySearch.java</exclude>
                   
                   
+                  
                   <exclude>**/TestImport.java</exclude>
                   <exclude>**/TestRollbackBigFiles.java</exclude>
                   <exclude>**/TestErrorMultithreading.java</exclude>
@@ -486,7 +509,8 @@
                         <include>org/exoplatform/services/jcr/integration/PrepareTestRepository.java</include>
                      </includes>
                   </configuration>
-               </execution -->
+               </execution
+-->
                <execution>
                   <id>execution4 - pause 10 sec</id>
                   <phase>test</phase>

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerEntryWrapper.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerEntryWrapper.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/config/QueryHandlerEntryWrapper.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -22,7 +22,6 @@
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.services.jcr.datamodel.IllegalNameException;
 import org.exoplatform.services.jcr.impl.Constants;
-import org.exoplatform.services.jcr.impl.core.query.ErrorLog;
 import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
 import org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext;
 import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
@@ -58,641 +57,624 @@
  * @version $Id: QueryHandlerEntry.java 14931 2008-05-29 15:02:08Z ksm $
  */
 
-public class QueryHandlerEntryWrapper implements QueryHandlerParams
-{
+public class QueryHandlerEntryWrapper implements QueryHandlerParams {
 
-   /**
-    * The default value for property {@link #extractorBackLog}.
-    */
-   public static final int DEFAULT_EXTRACTOR_BACKLOG = 100;
+    /**
+     * The default value for property {@link #extractorBackLog}.
+     */
+    public static final int DEFAULT_EXTRACTOR_BACKLOG = 100;
 
-   /**
-    * The default value for property {@link #extractorPoolSize}.
-    */
-   public static final int DEFAULT_EXTRACTOR_POOLSIZE = 0;
+    /**
+     * The default value for property {@link #extractorPoolSize}.
+     */
+    public static final int DEFAULT_EXTRACTOR_POOLSIZE = 0;
 
-   /**
-    * The default timeout in milliseconds which is granted to the text extraction process until
-    * fulltext indexing is deferred to a background thread.
-    */
-   public static final int DEFAULT_EXTRACTOR_TIMEOUT = 100;
+    /**
+     * The default timeout in milliseconds which is granted to the text
+     * extraction process until fulltext indexing is deferred to a background
+     * thread.
+     */
+    public static final int DEFAULT_EXTRACTOR_TIMEOUT = 100;
 
-   /**
-    * the default value for property {@link #maxFieldLength}.
-    */
-   public static final int DEFAULT_MAX_FIELD_LENGTH = 10000;
+    /**
+     * the default value for property {@link #maxFieldLength}.
+     */
+    public static final int DEFAULT_MAX_FIELD_LENGTH = 10000;
 
-   /**
-    * The default value for property {@link #maxMergeDocs}.
-    */
-   public static final int DEFAULT_MAX_MERGE_DOCS = Integer.MAX_VALUE;
+    /**
+     * The default value for property {@link #maxMergeDocs}.
+     */
+    public static final int DEFAULT_MAX_MERGE_DOCS = Integer.MAX_VALUE;
 
-   /**
-    * the default value for property {@link #mergeFactor}.
-    */
-   public static final int DEFAULT_MERGE_FACTOR = 10;
+    /**
+     * the default value for property {@link #mergeFactor}.
+     */
+    public static final int DEFAULT_MERGE_FACTOR = 10;
 
-   /**
-    * The default value for property {@link #minMergeDocs}.
-    */
-   public static final int DEFAULT_MIN_MERGE_DOCS = 100;
+    /**
+     * The default value for property {@link #minMergeDocs}.
+     */
+    public static final int DEFAULT_MIN_MERGE_DOCS = 100;
 
-   /**
-    * Name of the file to persist search internal namespace mappings.
-    */
-   public static final String NS_MAPPING_FILE = "ns_mappings.properties"; // TODO
+    /**
+     * Name of the file to persist search internal namespace mappings.
+     */
+    public static final String NS_MAPPING_FILE = "ns_mappings.properties"; // TODO
 
-   /**
-    * The excerpt provider class. Implements {@link ExcerptProvider}.
-    */
-   private static final String DEDAULT_EXCERPTPROVIDER_CLASS = DefaultHTMLExcerpt.class.getName();
+    /**
+     * The excerpt provider class. Implements {@link ExcerptProvider}.
+     */
+    private static final String DEDAULT_EXCERPTPROVIDER_CLASS = DefaultHTMLExcerpt.class
+	    .getName();
 
-   private static final String DEDAULT_INDEXINGCONFIGURATIONCLASS = IndexingConfigurationImpl.class.getName();
+    private static final String DEDAULT_INDEXINGCONFIGURATIONCLASS = IndexingConfigurationImpl.class
+	    .getName();
 
-   private static final boolean DEFAULT_AUTOREPAIR = true;
+    private static final boolean DEFAULT_AUTOREPAIR = true;
 
-   private static final int DEFAULT_BUFFER_SIZE = 10;
+    private static final int DEFAULT_BUFFER_SIZE = 10;
 
-   private static final int DEFAULT_CACHE_SIZE = 1000;
+    private static final int DEFAULT_CACHE_SIZE = 1000;
 
-   private final static boolean DEFAULT_CONSISTENCYCHECKENABLED = false;
+    private final static boolean DEFAULT_CONSISTENCYCHECKENABLED = false;
 
-   private final static boolean DEFAULT_DOCUMENTORDER = true;
+    private final static boolean DEFAULT_DOCUMENTORDER = true;
 
-   private final static boolean DEFAULT_FORCECONSISTENCYCHECK = false;
+    private final static boolean DEFAULT_FORCECONSISTENCYCHECK = false;
 
-   /**
-    * Name of the default query implementation class.
-    */
-   private static final String DEFAULT_QUERY_HANDLER_CLASS = SearchIndex.class.getName();
+    /**
+     * Name of the default query implementation class.
+     */
+    private static final String DEFAULT_QUERY_HANDLER_CLASS = SearchIndex.class
+	    .getName();
 
-   /**
-    * Name of the default query implementation class.
-    */
-   private static final String DEFAULT_QUERY_IMPL_CLASS = QueryImpl.class.getName();
+    /**
+     * Name of the default query implementation class.
+     */
+    private static final String DEFAULT_QUERY_IMPL_CLASS = QueryImpl.class
+	    .getName();
 
-   /**
-    * The number of documents that are pre fetched when a query is executed. <p/> Default value is:
-    * {@link Integer#MAX_VALUE}.
-    */
-   private final static int DEFAULT_RESULTFETCHSIZE = Integer.MAX_VALUE;
+    /**
+     * The number of documents that are pre fetched when a query is executed.
+     * <p/>
+     * Default value is: {@link Integer#MAX_VALUE}.
+     */
+    private final static int DEFAULT_RESULTFETCHSIZE = Integer.MAX_VALUE;
 
-   private final static boolean DEFAULT_SUPPORTHIGHLIGHTING = false;
+    private final static boolean DEFAULT_SUPPORTHIGHLIGHTING = false;
 
-   private final static boolean DEFAULT_USECOMPOUNDFILE = false;
+    private final static boolean DEFAULT_USECOMPOUNDFILE = false;
 
-   private final static int DEFAULT_VOLATILEIDLETIME = 3;
+    private final static int DEFAULT_VOLATILEIDLETIME = 3;
 
-   //since https://jira.jboss.org/jira/browse/EXOJCR-17
+    // since https://jira.jboss.org/jira/browse/EXOJCR-17
 
-   public static final boolean DEFAULT_UPGRADE_INDEX = false;
+    public static final boolean DEFAULT_UPGRADE_INDEX = false;
 
-   private QueryHandlerEntry queryHandlerEntry;
+    private QueryHandlerEntry queryHandlerEntry;
 
-   public QueryHandlerEntry getQueryHandlerEntry()
-   {
-      return queryHandlerEntry;
-   }
+    public QueryHandlerEntry getQueryHandlerEntry() {
+	return queryHandlerEntry;
+    }
 
-   private static void initDefaults(QueryHandlerEntry entry)
-   {
-      entry.putBooleanParameter(PARAM_AUTO_REPAIR, DEFAULT_AUTOREPAIR);
-      entry.putIntegerParameter(PARAM_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
-      entry.putIntegerParameter(PARAM_CACHE_SIZE, DEFAULT_CACHE_SIZE);
-      entry.putBooleanParameter(PARAM_DOCUMENT_ORDER, DEFAULT_DOCUMENTORDER);
-      entry.putParameterValue(PARAM_EXCERPTPROVIDER_CLASS, DEDAULT_EXCERPTPROVIDER_CLASS);
-      entry.putParameterValue(PARAM_EXCLUDED_NODE_IDENTIFERS, null);
-      entry.putIntegerParameter(PARAM_EXTRACTOR_BACKLOG, DEFAULT_EXTRACTOR_BACKLOG);
-      entry.putIntegerParameter(PARAM_EXTRACTOR_POOLSIZE, DEFAULT_EXTRACTOR_POOLSIZE);
-      entry.putIntegerParameter(PARAM_EXTRACTOR_TIMEOUT, DEFAULT_EXTRACTOR_TIMEOUT);
-   }
+    private static void initDefaults(QueryHandlerEntry entry) {
+	entry.putBooleanParameter(PARAM_AUTO_REPAIR, DEFAULT_AUTOREPAIR);
+	entry.putIntegerParameter(PARAM_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+	entry.putIntegerParameter(PARAM_CACHE_SIZE, DEFAULT_CACHE_SIZE);
+	entry.putBooleanParameter(PARAM_DOCUMENT_ORDER, DEFAULT_DOCUMENTORDER);
+	entry.putParameterValue(PARAM_EXCERPTPROVIDER_CLASS,
+		DEDAULT_EXCERPTPROVIDER_CLASS);
+	entry.putParameterValue(PARAM_EXCLUDED_NODE_IDENTIFERS, null);
+	entry.putIntegerParameter(PARAM_EXTRACTOR_BACKLOG,
+		DEFAULT_EXTRACTOR_BACKLOG);
+	entry.putIntegerParameter(PARAM_EXTRACTOR_POOLSIZE,
+		DEFAULT_EXTRACTOR_POOLSIZE);
+	entry.putIntegerParameter(PARAM_EXTRACTOR_TIMEOUT,
+		DEFAULT_EXTRACTOR_TIMEOUT);
+    }
 
-   public String getType()
-   {
-      return queryHandlerEntry.getType();
-   }
+    public String getType() {
+	return queryHandlerEntry.getType();
+    }
 
-   public static QueryHandlerEntry queryHandlerEntryFactory()
-   {
-      QueryHandlerEntry entry = new QueryHandlerEntry();
-      initDefaults(entry);
-      return entry;
-   }
+    public static QueryHandlerEntry queryHandlerEntryFactory() {
+	QueryHandlerEntry entry = new QueryHandlerEntry();
+	initDefaults(entry);
+	return entry;
+    }
 
-   /** The logger instance for this class */
-   private static final Log log = ExoLogger.getLogger(QueryHandlerEntry.class);
+    /** The logger instance for this class */
+    private static final Log log = ExoLogger.getLogger(QueryHandlerEntry.class);
 
-   //public QueryHandlerEntry     queryHandler;
+    // public QueryHandlerEntry queryHandler;
 
-   public Integer volatileIdleTime;
+    public Integer volatileIdleTime;
 
-   /**
-    * The analyzer we use for indexing.
-    */
-   private JcrStandartAnalyzer analyzer;
+    /**
+     * The analyzer we use for indexing.
+     */
+    private JcrStandartAnalyzer analyzer;
 
-   private String queryHandlerClass = DEFAULT_QUERY_HANDLER_CLASS;
+    private String queryHandlerClass = DEFAULT_QUERY_HANDLER_CLASS;
 
-   public QueryHandlerEntryWrapper(QueryHandlerEntry queryHandlerEntry)
-   {
-      this.queryHandlerEntry = queryHandlerEntry;
-      this.analyzer = new JcrStandartAnalyzer();
-      initDefaults(queryHandlerEntry);
-   }
+    public QueryHandlerEntryWrapper(QueryHandlerEntry queryHandlerEntry) {
+	this.queryHandlerEntry = queryHandlerEntry;
+	this.analyzer = new JcrStandartAnalyzer();
+	initDefaults(queryHandlerEntry);
+    }
 
-   public QueryHandlerEntryWrapper(String type, List params, QueryHandlerEntry queryHandlerEntry)
-   {
-      this.queryHandlerEntry = queryHandlerEntry;
-      queryHandlerEntry.setType(type);
-      queryHandlerEntry.setParameters(params);
-      this.analyzer = new JcrStandartAnalyzer();
-      initDefaults(queryHandlerEntry);
-   }
+    public QueryHandlerEntryWrapper(String type, List params,
+	    QueryHandlerEntry queryHandlerEntry) {
+	this.queryHandlerEntry = queryHandlerEntry;
+	queryHandlerEntry.setType(type);
+	queryHandlerEntry.setParameters(params);
+	this.analyzer = new JcrStandartAnalyzer();
+	initDefaults(queryHandlerEntry);
+    }
 
-   /**
-    * Creates an excerpt provider for the given <code>query</code>.
-    * 
-    * @param query the query.
-    * @return an excerpt provider for the given <code>query</code>.
-    * @throws IOException if the provider cannot be created.
-    */
-   public ExcerptProvider createExcerptProvider(Query query) throws IOException
-   {
-      ExcerptProvider ep;
-      try
-      {
-         Class excerptProviderClass = Class.forName(getExcerptProviderClass(), true, this.getClass().getClassLoader());
-         ep = (ExcerptProvider)excerptProviderClass.newInstance();
-      }
-      catch (Exception e)
-      {
-         IOException ex = new IOException();
-         ex.initCause(e);
-         throw ex;
-      }
+    /**
+     * Creates an excerpt provider for the given <code>query</code>.
+     * 
+     * @param query
+     *            the query.
+     * @return an excerpt provider for the given <code>query</code>.
+     * @throws IOException
+     *             if the provider cannot be created.
+     */
+    public ExcerptProvider createExcerptProvider(Query query)
+	    throws IOException {
+	ExcerptProvider ep;
+	try {
+	    Class excerptProviderClass = Class.forName(
+		    getExcerptProviderClass(), true, this.getClass()
+			    .getClassLoader());
+	    ep = (ExcerptProvider) excerptProviderClass.newInstance();
+	} catch (Exception e) {
+	    IOException ex = new IOException();
+	    ex.initCause(e);
+	    throw ex;
+	}
 
-      return ep;
-   }
+	return ep;
+    }
 
-   /**
-    * @param namespaceMappings The namespace mappings
-    * @return the fulltext indexing configuration or <code>null</code> if there is no configuration.
-    */
-   public IndexingConfiguration createIndexingConfiguration(NamespaceMappings namespaceMappings,
-      QueryHandlerContext context, ConfigurationManager cfm) throws IOException, RepositoryConfigurationException
-   {
-      Element docElement = getIndexingConfigurationDOM(cfm);
-      if (docElement == null)
-      {
-         return null;
-      }
-      IndexingConfiguration idxCfg = null;
-      try
-      {
-         Class indexingConfigurationClass =
-            Class.forName(getIndexingConfigurationClass(), true, this.getClass().getClassLoader());
-         idxCfg = (IndexingConfiguration)indexingConfigurationClass.newInstance();
-         idxCfg.init(docElement, context, namespaceMappings);
-      }
-      catch (InstantiationException e)
-      {
-         log.warn("Exception initializing indexing configuration from: " + getIndexingConfigurationPath(), e);
-      }
-      catch (IllegalAccessException e)
-      {
-         log.warn("Exception initializing indexing configuration from: " + getIndexingConfigurationPath(), e);
-      }
-      catch (RepositoryException e)
-      {
-         log.warn("Exception initializing indexing configuration from: " + getIndexingConfigurationPath(), e);
-      }
-      catch (IllegalNameException e)
-      {
-         log.warn("Exception initializing indexing configuration from: " + getIndexingConfigurationPath(), e);
-      }
-      catch (Exception e)
-      {
-         log.warn("Exception initializing indexing configuration from: " + getIndexingConfigurationPath(), e);
-      }
-      return idxCfg;
-   }
+    /**
+     * @param namespaceMappings
+     *            The namespace mappings
+     * @return the fulltext indexing configuration or <code>null</code> if there
+     *         is no configuration.
+     */
+    public IndexingConfiguration createIndexingConfiguration(
+	    NamespaceMappings namespaceMappings, QueryHandlerContext context,
+	    ConfigurationManager cfm) throws IOException,
+	    RepositoryConfigurationException {
+	Element docElement = getIndexingConfigurationDOM(cfm);
+	if (docElement == null) {
+	    return null;
+	}
+	IndexingConfiguration idxCfg = null;
+	try {
+	    Class indexingConfigurationClass = Class.forName(
+		    getIndexingConfigurationClass(), true, this.getClass()
+			    .getClassLoader());
+	    idxCfg = (IndexingConfiguration) indexingConfigurationClass
+		    .newInstance();
+	    idxCfg.init(docElement, context, namespaceMappings);
+	} catch (InstantiationException e) {
+	    log.warn("Exception initializing indexing configuration from: "
+		    + getIndexingConfigurationPath(), e);
+	} catch (IllegalAccessException e) {
+	    log.warn("Exception initializing indexing configuration from: "
+		    + getIndexingConfigurationPath(), e);
+	} catch (RepositoryException e) {
+	    log.warn("Exception initializing indexing configuration from: "
+		    + getIndexingConfigurationPath(), e);
+	} catch (IllegalNameException e) {
+	    log.warn("Exception initializing indexing configuration from: "
+		    + getIndexingConfigurationPath(), e);
+	} catch (Exception e) {
+	    log.warn("Exception initializing indexing configuration from: "
+		    + getIndexingConfigurationPath(), e);
+	}
+	return idxCfg;
+    }
 
-   /**
-    * Creates a spell checker for this query handler.
-    * 
-    * @return the spell checker or <code>null</code> if none is configured or an error occurs.
-    */
-   public SpellChecker createSpellChecker(QueryHandler handler)
-   {
-      SpellChecker spCheck = null;
-      if (getSpellCheckerClass() != null)
-      {
-         try
-         {
-            Class spellCheckerClass = Class.forName(getSpellCheckerClass(), true, this.getClass().getClassLoader());
-            spCheck = (SpellChecker)spellCheckerClass.newInstance();
-            spCheck.init(handler);
-         }
-         catch (Exception e)
-         {
-            log.warn("Exception initializing spell checker: " + getSpellCheckerClass(), e);
-         }
-      }
-      return spCheck;
-   }
+    /**
+     * Creates a spell checker for this query handler.
+     * 
+     * @return the spell checker or <code>null</code> if none is configured or
+     *         an error occurs.
+     */
+    public SpellChecker createSpellChecker(QueryHandler handler) {
+	SpellChecker spCheck = null;
+	if (getSpellCheckerClass() != null) {
+	    try {
+		Class spellCheckerClass = Class.forName(getSpellCheckerClass(),
+			true, this.getClass().getClassLoader());
+		spCheck = (SpellChecker) spellCheckerClass.newInstance();
+		spCheck.init(handler);
+	    } catch (Exception e) {
+		log.warn("Exception initializing spell checker: "
+			+ getSpellCheckerClass(), e);
+	    }
+	}
+	return spCheck;
+    }
 
-   /**
-    * @param cfm
-    * @return the configured synonym provider or <code>null</code> if none is configured or an error
-    *         occurs.
-    */
-   public SynonymProvider createSynonymProvider(ConfigurationManager cfm)
-   {
-      SynonymProvider sp = null;
-      if (getSynonymProviderClass() != null)
-      {
-         try
-         {
-            Class synonymProviderClass =
-               Class.forName(getSynonymProviderClass(), true, this.getClass().getClassLoader());
-            sp = (SynonymProvider)synonymProviderClass.newInstance();
+    /**
+     * @param cfm
+     * @return the configured synonym provider or <code>null</code> if none is
+     *         configured or an error occurs.
+     */
+    public SynonymProvider createSynonymProvider(ConfigurationManager cfm) {
+	SynonymProvider sp = null;
+	if (getSynonymProviderClass() != null) {
+	    try {
+		Class synonymProviderClass = Class.forName(
+			getSynonymProviderClass(), true, this.getClass()
+				.getClassLoader());
+		sp = (SynonymProvider) synonymProviderClass.newInstance();
 
-            sp.initialize(createSynonymProviderConfigResource(cfm));
-         }
-         catch (Exception e)
-         {
-            log.warn("Exception initializing synonym provider: " + getSynonymProviderClass(), e);
-            sp = null;
-         }
-      }
-      return sp;
-   }
+		sp.initialize(createSynonymProviderConfigResource(cfm));
+	    } catch (Exception e) {
+		log.warn("Exception initializing synonym provider: "
+			+ getSynonymProviderClass(), e);
+		sp = null;
+	    }
+	}
+	return sp;
+    }
 
-   public JcrStandartAnalyzer getAnalyzer()
-   {
-      return analyzer;
-   }
+    public JcrStandartAnalyzer getAnalyzer() {
+	return analyzer;
+    }
 
-   private String getParameterString(String name)
-   {
-      return queryHandlerEntry.getParameterValue(name, null);
-   }
+    private String getParameterString(String name) {
+	return queryHandlerEntry.getParameterValue(name, null);
+    }
 
-   private Integer getParameterIntegerInitialized(String name)
-   {
-      String value = queryHandlerEntry.getParameterValue(name, null);
-      return StringNumberParser.parseInt(value);
-   }
+    private Integer getParameterIntegerInitialized(String name) {
+	String value = queryHandlerEntry.getParameterValue(name, null);
+	return StringNumberParser.parseInt(value);
+    }
 
-   private Boolean getParameterBooleanInitialized(String name)
-   {
-      String value = queryHandlerEntry.getParameterValue(name, "false");
-      return Boolean.parseBoolean(value);
-   }
+    private Boolean getParameterBooleanInitialized(String name) {
+	String value = queryHandlerEntry.getParameterValue(name, "false");
+	return Boolean.parseBoolean(value);
+    }
 
-   /**
-    * If set <code>true</code> errors detected by the consistency check are repaired. If
-    * <code>false</code> the errors are only reported in the log. <p/> Default value is:
-    * <code>true</code>.
-    * @throws RepositoryConfigurationException 
-    */
-   public boolean getAutoRepair() throws RepositoryConfigurationException
-   {
-      return getParameterBooleanInitialized(PARAM_AUTO_REPAIR);
-   }
+    /**
+     * If set <code>true</code> errors detected by the consistency check are
+     * repaired. If <code>false</code> the errors are only reported in the log.
+     * <p/>
+     * Default value is: <code>true</code>.
+     * 
+     * @throws RepositoryConfigurationException
+     */
+    public boolean getAutoRepair() throws RepositoryConfigurationException {
+	return getParameterBooleanInitialized(PARAM_AUTO_REPAIR);
+    }
 
-   /**
-    * Number of documents that are buffered before they are added to the index.
-    * @throws RepositoryConfigurationException 
-    */
-   public int getBufferSize()
-   {
-      return getParameterIntegerInitialized(PARAM_BUFFER_SIZE);
-   }
+    /**
+     * Number of documents that are buffered before they are added to the index.
+     * 
+     * @throws RepositoryConfigurationException
+     */
+    public int getBufferSize() {
+	return getParameterIntegerInitialized(PARAM_BUFFER_SIZE);
+    }
 
-   public int getCacheSize()
-   {
-      return getParameterIntegerInitialized(PARAM_CACHE_SIZE);
-   }
+    public int getCacheSize() {
+	return getParameterIntegerInitialized(PARAM_CACHE_SIZE);
+    }
 
-   /**
-    * Flag indicating whether document order is enable as the default ordering.
-    */
-   public boolean getDocumentOrder()
-   {
-      return getParameterBooleanInitialized(PARAM_DOCUMENT_ORDER);
-   }
+    /**
+     * Flag indicating whether document order is enable as the default ordering.
+     */
+    public boolean getDocumentOrder() {
+	return getParameterBooleanInitialized(PARAM_DOCUMENT_ORDER);
+    }
 
-   /**
-    * @return the class name of the excerpt provider implementation.
-    */
-   public String getExcerptProviderClass()
-   {
-      return getParameterString(PARAM_EXCERPTPROVIDER_CLASS);
-   }
+    /**
+     * @return the class name of the excerpt provider implementation.
+     */
+    public String getExcerptProviderClass() {
+	return getParameterString(PARAM_EXCERPTPROVIDER_CLASS);
+    }
 
-   public String getExcludedNodeIdentifers()
-   {
-      return getParameterString(PARAM_EXCLUDED_NODE_IDENTIFERS);
-   }
+    public String getExcludedNodeIdentifers() {
+	return getParameterString(PARAM_EXCLUDED_NODE_IDENTIFERS);
+    }
 
-   /**
-    * @return the size of the extractor queue back log.
-    */
-   public int getExtractorBackLogSize()
-   {
-      return getParameterIntegerInitialized(PARAM_EXTRACTOR_BACKLOG);
-   }
+    /**
+     * @return the size of the extractor queue back log.
+     */
+    public int getExtractorBackLogSize() {
+	return getParameterIntegerInitialized(PARAM_EXTRACTOR_BACKLOG);
+    }
 
-   /**
-    * @return the size of the thread pool which is used to run the text extractors when binary
-    *         content is indexed.
-    */
-   public int getExtractorPoolSize()
-   {
-      return getParameterIntegerInitialized(PARAM_EXTRACTOR_POOLSIZE);
-   }
+    /**
+     * @return the size of the thread pool which is used to run the text
+     *         extractors when binary content is indexed.
+     */
+    public int getExtractorPoolSize() {
+	return getParameterIntegerInitialized(PARAM_EXTRACTOR_POOLSIZE);
+    }
 
-   /**
-    * @return the extractor timeout in milliseconds.
-    */
-   public long getExtractorTimeout()
-   {
-      return getParameterIntegerInitialized(PARAM_EXTRACTOR_TIMEOUT);
-   }
+    /**
+     * @return the extractor timeout in milliseconds.
+     */
+    public long getExtractorTimeout() {
+	return getParameterIntegerInitialized(PARAM_EXTRACTOR_TIMEOUT);
+    }
 
-   /**
-    * Returns the location of the search index. Returns <code>null</code> if not set.
-    * 
-    * @return the location of the search index.
-    * @throws RepositoryConfigurationException
-    */
-   public String getIndexDir() throws RepositoryConfigurationException
-   {
+    /**
+     * Returns the location of the search index. Returns <code>null</code> if
+     * not set.
+     * 
+     * @return the location of the search index.
+     * @throws RepositoryConfigurationException
+     */
+    public String getIndexDir() throws RepositoryConfigurationException {
 
-      String indexDir;
-      try
-      {
-         indexDir = queryHandlerEntry.getParameterValue(PARAM_INDEX_DIR);
-      }
-      catch (RepositoryConfigurationException e)
-      {
-         indexDir = queryHandlerEntry.getParameterValue(OLD_PARAM_INDEX_DIR);
-      }
+	String indexDir;
+	try {
+	    indexDir = queryHandlerEntry.getParameterValue(PARAM_INDEX_DIR);
+	} catch (RepositoryConfigurationException e) {
+	    indexDir = queryHandlerEntry.getParameterValue(OLD_PARAM_INDEX_DIR);
+	}
 
-      indexDir = indexDir.replace("${java.io.tmpdir}", System.getProperty("java.io.tmpdir"));
+	indexDir = indexDir.replace("${java.io.tmpdir}", System
+		.getProperty("java.io.tmpdir"));
 
-      return indexDir;
-   }
+	return indexDir;
+    }
 
-   /**
-    * @return the class name of the indexing configuration implementation.
-    */
-   public String getIndexingConfigurationClass()
-   {
-      return queryHandlerEntry
-         .getParameterValue(PARAM_INDEXING_CONFIGURATION_CLASS, DEDAULT_INDEXINGCONFIGURATIONCLASS);
-   }
+    /**
+     * @return the class name of the indexing configuration implementation.
+     */
+    public String getIndexingConfigurationClass() {
+	return queryHandlerEntry.getParameterValue(
+		PARAM_INDEXING_CONFIGURATION_CLASS,
+		DEDAULT_INDEXINGCONFIGURATIONCLASS);
+    }
 
-   /**
-    * @return the path to the indexing configuration file.
-    */
-   public String getIndexingConfigurationPath()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_INDEXING_CONFIGURATION_PATH, null);
-   }
+    /**
+     * @return the path to the indexing configuration file.
+     */
+    public String getIndexingConfigurationPath() {
+	return queryHandlerEntry.getParameterValue(
+		PARAM_INDEXING_CONFIGURATION_PATH, null);
+    }
 
-   public int getMaxFieldLength()
-   {
-      return queryHandlerEntry.getParameterInteger(PARAM_MAX_FIELD_LENGTH, DEFAULT_MAX_FIELD_LENGTH);
-   }
+    public int getMaxFieldLength() {
+	return queryHandlerEntry.getParameterInteger(PARAM_MAX_FIELD_LENGTH,
+		DEFAULT_MAX_FIELD_LENGTH);
+    }
 
-   /**
-    * Returns the current value for maxMergeDocs.
-    * 
-    * @return the current value for maxMergeDocs.
-    */
-   public int getMaxMergeDocs()
-   {
-      return queryHandlerEntry.getParameterInteger(PARAM_MAX_MERGE_DOCS, DEFAULT_MAX_MERGE_DOCS);
-   }
+    /**
+     * Returns the current value for maxMergeDocs.
+     * 
+     * @return the current value for maxMergeDocs.
+     */
+    public int getMaxMergeDocs() {
+	return queryHandlerEntry.getParameterInteger(PARAM_MAX_MERGE_DOCS,
+		DEFAULT_MAX_MERGE_DOCS);
+    }
 
-   /**
-    * Returns the current value for the merge factor.
-    * 
-    * @return the current value for the merge factor.
-    */
-   public int getMergeFactor()
-   {
-      return queryHandlerEntry.getParameterInteger(PARAM_MERGE_FACTOR, DEFAULT_MERGE_FACTOR);
-   }
+    /**
+     * Returns the current value for the merge factor.
+     * 
+     * @return the current value for the merge factor.
+     */
+    public int getMergeFactor() {
+	return queryHandlerEntry.getParameterInteger(PARAM_MERGE_FACTOR,
+		DEFAULT_MERGE_FACTOR);
+    }
 
-   /**
-    * Returns the current value for minMergeDocs.
-    * 
-    * @return the current value for minMergeDocs.
-    */
-   public int getMinMergeDocs()
-   {
-      return queryHandlerEntry.getParameterInteger(PARAM_MIN_MERGE_DOCS, DEFAULT_MIN_MERGE_DOCS);
-   }
+    /**
+     * Returns the current value for minMergeDocs.
+     * 
+     * @return the current value for minMergeDocs.
+     */
+    public int getMinMergeDocs() {
+	return queryHandlerEntry.getParameterInteger(PARAM_MIN_MERGE_DOCS,
+		DEFAULT_MIN_MERGE_DOCS);
+    }
 
-   public String getQueryClass()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_QUERY_CLASS, DEFAULT_QUERY_IMPL_CLASS);
-   }
+    public String getQueryClass() {
+	return queryHandlerEntry.getParameterValue(PARAM_QUERY_CLASS,
+		DEFAULT_QUERY_IMPL_CLASS);
+    }
 
-   /**
-    * @return the number of results the query handler will fetch initially when a query is executed.
-    */
-   public int getResultFetchSize()
-   {
-      return queryHandlerEntry.getParameterInteger(PARAM_RESULT_FETCH_SIZE, DEFAULT_RESULTFETCHSIZE);
-   }
+    /**
+     * @return the number of results the query handler will fetch initially when
+     *         a query is executed.
+     */
+    public int getResultFetchSize() {
+	return queryHandlerEntry.getParameterInteger(PARAM_RESULT_FETCH_SIZE,
+		DEFAULT_RESULTFETCHSIZE);
+    }
 
-   public String getRootNodeIdentifer()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_ROOT_NODE_ID, Constants.ROOT_UUID);
-   }
+    public String getRootNodeIdentifer() {
+	return queryHandlerEntry.getParameterValue(PARAM_ROOT_NODE_ID,
+		Constants.ROOT_UUID);
+    }
 
-   /**
-    * Get spell checker class.
-    * 
-    * @return the class name of the spell checker implementation or <code>null</code> if none is set.
-    */
-   public String getSpellCheckerClass()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_SPELLCHECKER_CLASS, null);
-   }
+    /**
+     * Get spell checker class.
+     * 
+     * @return the class name of the spell checker implementation or
+     *         <code>null</code> if none is set.
+     */
+    public String getSpellCheckerClass() {
+	return queryHandlerEntry.getParameterValue(PARAM_SPELLCHECKER_CLASS,
+		null);
+    }
 
-   /**
-    * Get support highlighting.
-    * 
-    * @return <code>true</code> if highlighting support is enabled.
-    */
-   public boolean getSupportHighlighting()
-   {
-      return queryHandlerEntry.getParameterBoolean(PARAM_SUPPORT_HIGHLIGHTING, DEFAULT_SUPPORTHIGHLIGHTING);
-   }
+    /**
+     * Get support highlighting.
+     * 
+     * @return <code>true</code> if highlighting support is enabled.
+     */
+    public boolean getSupportHighlighting() {
+	return queryHandlerEntry.getParameterBoolean(
+		PARAM_SUPPORT_HIGHLIGHTING, DEFAULT_SUPPORTHIGHLIGHTING);
+    }
 
-   /**
-    * Get synonym provider class.
-    * 
-    * @return the class name of the synonym provider implementation or <code>null</code> if none is
-    *         set.
-    */
-   public String getSynonymProviderClass()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_SYNONYMPROVIDER_CLASS, null);
-   }
+    /**
+     * Get synonym provider class.
+     * 
+     * @return the class name of the synonym provider implementation or
+     *         <code>null</code> if none is set.
+     */
+    public String getSynonymProviderClass() {
+	return queryHandlerEntry.getParameterValue(PARAM_SYNONYMPROVIDER_CLASS,
+		null);
+    }
 
-   /**
-    * Get synonym provider configuration path.
-    * 
-    * @return the configuration path for the synonym provider. If none is set this method returns
-    *         <code>null</code>.
-    */
-   public String getSynonymProviderConfigPath()
-   {
-      return queryHandlerEntry.getParameterValue(PARAM_SYNONYMPROVIDER_CONFIG_PATH, null);
-   }
+    /**
+     * Get synonym provider configuration path.
+     * 
+     * @return the configuration path for the synonym provider. If none is set
+     *         this method returns <code>null</code>.
+     */
+    public String getSynonymProviderConfigPath() {
+	return queryHandlerEntry.getParameterValue(
+		PARAM_SYNONYMPROVIDER_CONFIG_PATH, null);
+    }
 
-   /**
-    * Returns the current value for useCompoundFile.
-    * 
-    * @return the current value for useCompoundFile.
-    */
-   public boolean getUseCompoundFile()
-   {
-      return queryHandlerEntry.getParameterBoolean(PARAM_USE_COMPOUNDFILE, DEFAULT_USECOMPOUNDFILE);
-   }
+    /**
+     * Returns the current value for useCompoundFile.
+     * 
+     * @return the current value for useCompoundFile.
+     */
+    public boolean getUseCompoundFile() {
+	return queryHandlerEntry.getParameterBoolean(PARAM_USE_COMPOUNDFILE,
+		DEFAULT_USECOMPOUNDFILE);
+    }
 
-   /**
-    * Returns the current value for volatileIdleTime.
-    * 
-    * @return the current value for volatileIdleTime.
-    */
-   public int getVolatileIdleTime()
-   {
-      if (volatileIdleTime == null)
-         volatileIdleTime = queryHandlerEntry.getParameterInteger(PARAM_VOLATILE_IDLE_TIME, DEFAULT_VOLATILEIDLETIME);
+    /**
+     * Returns the current value for volatileIdleTime.
+     * 
+     * @return the current value for volatileIdleTime.
+     */
+    public int getVolatileIdleTime() {
+	if (volatileIdleTime == null)
+	    volatileIdleTime = queryHandlerEntry.getParameterInteger(
+		    PARAM_VOLATILE_IDLE_TIME, DEFAULT_VOLATILEIDLETIME);
 
-      return volatileIdleTime;
-   }
+	return volatileIdleTime;
+    }
 
-   /**
-    * If set <code>true</code> the index is checked for consistency depending on the
-    * {@link #forceConsistencyCheck} parameter. If set to <code>false</code>, no consistency check is
-    * performed, even if the redo log had been applied on startup. <p/> Default value is:
-    * <code>false</code>.
-    * 
-    * @return boolean
-    */
-   public boolean isConsistencyCheckEnabled()
-   {
-      return queryHandlerEntry.getParameterBoolean(PARAM_CONSISTENCY_CHECK_ENABLED, DEFAULT_CONSISTENCYCHECKENABLED);
-   }
+    /**
+     * If set <code>true</code> the index is checked for consistency depending
+     * on the {@link #forceConsistencyCheck} parameter. If set to
+     * <code>false</code>, no consistency check is performed, even if the redo
+     * log had been applied on startup.
+     * <p/>
+     * Default value is: <code>false</code>.
+     * 
+     * @return boolean
+     */
+    public boolean isConsistencyCheckEnabled() {
+	return queryHandlerEntry.getParameterBoolean(
+		PARAM_CONSISTENCY_CHECK_ENABLED,
+		DEFAULT_CONSISTENCYCHECKENABLED);
+    }
 
-   public boolean isForceConsistencyCheck()
-   {
-      return queryHandlerEntry.getParameterBoolean(PARAM_FORCE_CONSISTENCYCHECK, DEFAULT_FORCECONSISTENCYCHECK);
-   }
+    public boolean isForceConsistencyCheck() {
+	return queryHandlerEntry.getParameterBoolean(
+		PARAM_FORCE_CONSISTENCYCHECK, DEFAULT_FORCECONSISTENCYCHECK);
+    }
 
-   /**
-    * 
-    * @return true if index upgrade allowed.
-    */
-   public boolean isUpgradeIndex()
-   {
-      Boolean updateIndex = queryHandlerEntry.getParameterBoolean(PARAM_UPGRADE_INDEX, null);
-      if (updateIndex == null || !updateIndex)
-      {
-         updateIndex = Boolean.valueOf(System.getProperty(PARAM_UPGRADE_INDEX));
-      }
-      return updateIndex;
-   }
+    /**
+     * 
+     * @return true if index upgrade allowed.
+     */
+    public boolean isUpgradeIndex() {
+	Boolean updateIndex = queryHandlerEntry.getParameterBoolean(
+		PARAM_UPGRADE_INDEX, null);
+	if (updateIndex == null || !updateIndex) {
+	    updateIndex = Boolean.valueOf(System
+		    .getProperty(PARAM_UPGRADE_INDEX));
+	}
+	return updateIndex;
+    }
 
-   /**
-    * Creates a file system resource to the synonym provider configuration.
-    * 
-    * @param cfm
-    * @return a file system resource or <code>null</code> if no path was configured.
-    * @throws Exception
-    */
-   protected InputStream createSynonymProviderConfigResource(ConfigurationManager cfm) throws Exception
-   {
-      if (getSynonymProviderConfigPath() != null)
-      {
-         return cfm.getInputStream(getSynonymProviderConfigPath());
-      }
-      return null;
-   }
+    /**
+     * Creates a file system resource to the synonym provider configuration.
+     * 
+     * @param cfm
+     * @return a file system resource or <code>null</code> if no path was
+     *         configured.
+     * @throws Exception
+     */
+    protected InputStream createSynonymProviderConfigResource(
+	    ConfigurationManager cfm) throws Exception {
+	if (getSynonymProviderConfigPath() != null) {
+	    return cfm.getInputStream(getSynonymProviderConfigPath());
+	}
+	return null;
+    }
 
-   /**
-    * Returns the document element of the indexing configuration or <code>null</code> if there is no
-    * indexing configuration.
-    * 
-    * @return the indexing configuration or <code>null</code> if there is none.
-    * @throws IOException
-    * @throws RepositoryConfigurationException
-    */
-   protected Element getIndexingConfigurationDOM(ConfigurationManager cfm) throws IOException,
-      RepositoryConfigurationException
-   {
-      String indexingConfigPath = getIndexingConfigurationPath();
-      Element indexingConfiguration = null;
-      if (indexingConfigPath != null)
-      {
+    /**
+     * Returns the document element of the indexing configuration or
+     * <code>null</code> if there is no indexing configuration.
+     * 
+     * @return the indexing configuration or <code>null</code> if there is none.
+     * @throws IOException
+     * @throws RepositoryConfigurationException
+     */
+    protected Element getIndexingConfigurationDOM(ConfigurationManager cfm)
+	    throws IOException, RepositoryConfigurationException {
+	String indexingConfigPath = getIndexingConfigurationPath();
+	Element indexingConfiguration = null;
+	if (indexingConfigPath != null) {
 
-         InputStream is;
-         try
-         {
-            is = cfm.getInputStream(indexingConfigPath);
-         }
-         catch (Exception e1)
-         {
-            throw new IOException(e1.getLocalizedMessage());
-         }
+	    InputStream is;
+	    try {
+		is = cfm.getInputStream(indexingConfigPath);
+	    } catch (Exception e1) {
+		throw new IOException(e1.getLocalizedMessage());
+	    }
 
-         if (is == null)
-            throw new IOException("Resource does not exist: " + indexingConfigPath);
+	    if (is == null)
+		throw new IOException("Resource does not exist: "
+			+ indexingConfigPath);
 
-         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-         try
-         {
-            DocumentBuilder builder = factory.newDocumentBuilder();
-            builder.setEntityResolver(new IndexingConfigurationEntityResolver());
-            indexingConfiguration = builder.parse(is).getDocumentElement();
-         }
-         catch (ParserConfigurationException e)
-         {
-            throw new RepositoryConfigurationException(e.getLocalizedMessage(), e);
-         }
-         catch (SAXException e)
-         {
-            throw new RepositoryConfigurationException(e.getLocalizedMessage(), e);
-         }
-      }
+	    DocumentBuilderFactory factory = DocumentBuilderFactory
+		    .newInstance();
+	    try {
+		DocumentBuilder builder = factory.newDocumentBuilder();
+		builder
+			.setEntityResolver(new IndexingConfigurationEntityResolver());
+		indexingConfiguration = builder.parse(is).getDocumentElement();
+	    } catch (ParserConfigurationException e) {
+		throw new RepositoryConfigurationException(e
+			.getLocalizedMessage(), e);
+	    } catch (SAXException e) {
+		throw new RepositoryConfigurationException(e
+			.getLocalizedMessage(), e);
+	    }
+	}
 
-      return indexingConfiguration;
-   }
+	return indexingConfiguration;
+    }
 
-   /**
-    * Return ErrorLog file size in Kb String representation.
-    * 
-    * @return int size in Kb
-    */
-   public int getErrorLogSize()
-   {
-      String size = queryHandlerEntry.getParameterValue(PARAM_ERRORLOG_SIZE, null);
-      if ((size == null) || (size.equals("")))
-      {
-         return ErrorLog.DEFAULT_FILE_SIZE;
-      }
-      else
-      {
-         return new Integer(size);
-      }
-   }
+    /**
+     * Return ErrorLog file size in Kb String representation.
+     * 
+     * @return int size in Kb
+     */
+    public int getErrorLogSize() {
+	String size = queryHandlerEntry.getParameterValue(PARAM_ERRORLOG_SIZE,
+		null);
+	if ((size == null) || (size.equals(""))) {
+	    return SearchIndex.DEFAULT_ERRORLOG_FILE_SIZE;
+	} else {
+	    return new Integer(size);
+	}
+    }
 
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/core/nodetype/NodeTypeDataManager.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/core/nodetype/NodeTypeDataManager.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/core/nodetype/NodeTypeDataManager.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -23,7 +23,6 @@
 import org.exoplatform.services.jcr.dataflow.PlainChangesLog;
 import org.exoplatform.services.jcr.datamodel.InternalQName;
 import org.exoplatform.services.jcr.datamodel.NodeData;
-import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
 
 import java.io.InputStream;
 import java.util.List;
@@ -51,7 +50,7 @@
     */
    public Set<InternalQName> getSupertypes(final InternalQName nodeTypeName);
 
-   void addQueryHandler(QueryHandler queryHandler);
+   //void addQueryHandler(QueryHandler queryHandler);
 
    /**
     * @param nodeName

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/RepositoryContainer.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -31,7 +31,6 @@
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
 import org.exoplatform.services.jcr.config.RepositoryEntry;
 import org.exoplatform.services.jcr.config.WorkspaceEntry;
-import org.exoplatform.services.jcr.core.ManageableRepository;
 import org.exoplatform.services.jcr.core.nodetype.ExtendedNodeTypeManager;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
 import org.exoplatform.services.jcr.impl.core.LocationFactory;
@@ -49,6 +48,7 @@
 import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeManagerImpl;
 import org.exoplatform.services.jcr.impl.core.observation.ObservationManagerRegistry;
 import org.exoplatform.services.jcr.impl.core.query.QueryManagerFactory;
+import org.exoplatform.services.jcr.impl.core.query.RepositoryIndexSearcherHolder;
 import org.exoplatform.services.jcr.impl.core.query.SearchManager;
 import org.exoplatform.services.jcr.impl.core.query.SystemSearchManager;
 import org.exoplatform.services.jcr.impl.core.query.SystemSearchManagerHolder;
@@ -449,28 +449,28 @@
          WorkspaceContainer workspaceContainer = getWorkspaceContainer(ws.getName());
          SearchManager searchManager =
             (SearchManager)workspaceContainer.getComponentInstanceOfType(SearchManager.class);
-         if (searchManager != null)
-         {
-            typeManager.addQueryHandler(searchManager.getHandler());
-            namespaceRegistry.addQueryHandler(searchManager.getHandler());
-         }
-         else
-         {
-            log.warn("Search manager not configured for " + ws.getName());
-         }
+         //         if (searchManager != null)
+         //         {
+         //            typeManager.addQueryHandler(searchManager.getHandler());
+         //            namespaceRegistry.addQueryHandler(searchManager.getHandler());
+         //         }
+         //         else
+         //         {
+         //            log.warn("Search manager not configured for " + ws.getName());
+         //         }
       }
 
       SystemSearchManagerHolder searchManager =
          (SystemSearchManagerHolder)this.getComponentInstanceOfType(SystemSearchManagerHolder.class);
-      if (searchManager != null)
-      {
-         typeManager.addQueryHandler(searchManager.get().getHandler());
-         namespaceRegistry.addQueryHandler(searchManager.get().getHandler());
-      }
-      else
-      {
-         log.warn("System search manager not configured ");
-      }
+      //      if (searchManager != null)
+      //      {
+      //         typeManager.addQueryHandler(searchManager.get().getHandler());
+      //         namespaceRegistry.addQueryHandler(searchManager.get().getHandler());
+      //      }
+      //      else
+      //      {
+      //         log.warn("System search manager not configured ");
+      //      }
 
    }
 
@@ -603,6 +603,8 @@
 
       registerComponentImplementation(IdGenerator.class);
 
+      registerComponentImplementation(RepositoryIndexSearcherHolder.class);
+
       registerComponentImplementation(NamespaceDataPersister.class);
       registerComponentImplementation(NamespaceRegistryImpl.class);
 

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/NamespaceRegistryImpl.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/NamespaceRegistryImpl.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/NamespaceRegistryImpl.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -18,42 +18,21 @@
  */
 package org.exoplatform.services.jcr.impl.core;
 
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.WildcardQuery;
-import org.apache.lucene.search.BooleanClause.Occur;
 import org.exoplatform.services.jcr.dataflow.DataManager;
-import org.exoplatform.services.jcr.datamodel.InternalQName;
 import org.exoplatform.services.jcr.datamodel.ItemData;
-import org.exoplatform.services.jcr.datamodel.NodeData;
-import org.exoplatform.services.jcr.datamodel.PropertyData;
-import org.exoplatform.services.jcr.datamodel.QPath;
-import org.exoplatform.services.jcr.datamodel.ValueData;
-import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
-import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
-import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
-import org.exoplatform.services.jcr.impl.core.query.lucene.ScoreNode;
-import org.exoplatform.services.jcr.impl.core.value.NameValue;
-import org.exoplatform.services.jcr.impl.core.value.PathValue;
-import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
-import org.exoplatform.services.jcr.impl.dataflow.AbstractValueData;
+import org.exoplatform.services.jcr.impl.core.query.RepositoryIndexSearcherHolder;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
 
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
-import javax.jcr.Value;
 
 /**
  * Created by The eXo Platform SAS.
@@ -115,8 +94,10 @@
 
    private Map<String, String> prefixes;
 
-   private HashSet<QueryHandler> queryHandlers;
+   // private HashSet<QueryHandler> queryHandlers;
 
+   private final RepositoryIndexSearcherHolder indexSearcherHolder;
+
    // private final NodeTypeDataManager nodeTypeDataManager;
 
    /**
@@ -126,18 +107,20 @@
    {
       this.namespaces = DEF_NAMESPACES;
       this.prefixes = DEF_PREFIXES;
-      this.queryHandlers = new HashSet<QueryHandler>();
+      this.indexSearcherHolder = new RepositoryIndexSearcherHolder();
+      // this.queryHandlers = new HashSet<QueryHandler>();
       // this.nodeTypeDataManager = null;
    }
 
-   public NamespaceRegistryImpl(NamespaceDataPersister persister)
+   public NamespaceRegistryImpl(NamespaceDataPersister persister, RepositoryIndexSearcherHolder indexSearcherHolder)
    {
 
+      this.indexSearcherHolder = indexSearcherHolder;
       // this.nodeTypeDataManager = nodeTypeDataManager;
       this.namespaces = new HashMap<String, String>(DEF_NAMESPACES);
       this.prefixes = new HashMap<String, String>(DEF_PREFIXES);
       this.persister = persister;
-      this.queryHandlers = new HashSet<QueryHandler>();
+      // this.queryHandlers = new HashSet<QueryHandler>();
    }
 
    /**
@@ -340,10 +323,10 @@
       }
    }
 
-   public void addQueryHandler(QueryHandler queryHandler)
-   {
-      queryHandlers.add(queryHandler);
-   }
+   //   public void addQueryHandler(QueryHandler queryHandler)
+   //   {
+   //      queryHandlers.add(queryHandler);
+   //   }
 
    /**
     * Return
@@ -356,118 +339,118 @@
    public Set<String> getNodes(String prefix) throws RepositoryException
    {
 
-      LocationFactory locationFactory = new LocationFactory(this);
-      ValueFactoryImpl valueFactory = new ValueFactoryImpl(locationFactory);
+      //      LocationFactory locationFactory = new LocationFactory(this);
+      //      ValueFactoryImpl valueFactory = new ValueFactoryImpl(locationFactory);
+      //
+      //      BooleanQuery query = new BooleanQuery();
+      //      // query.add(new MatchAllDocsQuery(), Occur.MUST);
+      //      // name of the node
+      //      query.add(new WildcardQuery(new Term(FieldNames.LABEL, prefix + ":*")), Occur.SHOULD);
+      //      // name of the property
+      //      query.add(new WildcardQuery(new Term(FieldNames.PROPERTIES_SET, prefix + ":*")), Occur.SHOULD);
+      //
+      //      Set<String> result = getNodes(query);
+      //
+      //      // value of the property
+      //      Set<String> propSet = getNodes(new WildcardQuery(new Term(FieldNames.PROPERTIES, "*" + prefix + ":*")));
+      //      // Manually check property values;
+      //      for (String uuid : propSet)
+      //      {
+      //         if (isPrefixMatch(valueFactory, uuid, prefix))
+      //            result.add(uuid);
+      //      }
 
-      BooleanQuery query = new BooleanQuery();
-      // query.add(new MatchAllDocsQuery(), Occur.MUST);
-      // name of the node
-      query.add(new WildcardQuery(new Term(FieldNames.LABEL, prefix + ":*")), Occur.SHOULD);
-      // name of the property
-      query.add(new WildcardQuery(new Term(FieldNames.PROPERTIES_SET, prefix + ":*")), Occur.SHOULD);
-
-      Set<String> result = getNodes(query);
-
-      // value of the property
-      Set<String> propSet = getNodes(new WildcardQuery(new Term(FieldNames.PROPERTIES, "*" + prefix + ":*")));
-      // Manually check property values;
-      for (String uuid : propSet)
-      {
-         if (isPrefixMatch(valueFactory, uuid, prefix))
-            result.add(uuid);
-      }
-
-      return result;
+      return indexSearcherHolder.getNodesByUri(prefix);
    }
 
-   /**
-    * @param valueFactory
-    * @param dm
-    * @param uuid
-    * @param prefix
-    * @throws RepositoryException
-    */
-   private boolean isPrefixMatch(ValueFactoryImpl valueFactory, String uuid, String prefix) throws RepositoryException
-   {
-      DataManager dm = persister.getDataManager();
-      ItemData node = dm.getItemData(uuid);
-      if (node != null && node.isNode())
-      {
-         List<PropertyData> props = dm.getChildPropertiesData((NodeData)node);
-         for (PropertyData propertyData : props)
-         {
-            if (propertyData.getType() == PropertyType.PATH || propertyData.getType() == PropertyType.NAME)
-            {
-               for (ValueData vdata : propertyData.getValues())
-               {
-                  Value val =
-                     valueFactory.loadValue(((AbstractValueData)vdata).createTransientCopy(), propertyData.getType());
-                  if (propertyData.getType() == PropertyType.PATH)
-                  {
-                     if (isPrefixMatch(((PathValue)val).getQPath(), prefix))
-                        return true;
-                  }
-                  else if (propertyData.getType() == PropertyType.NAME)
-                  {
-                     if (isPrefixMatch(((NameValue)val).getQName(), prefix))
-                        return true;
-                  }
-               }
-            }
-         }
-      }
-      return false;
-   }
+   //   /**
+   //    * @param valueFactory
+   //    * @param dm
+   //    * @param uuid
+   //    * @param prefix
+   //    * @throws RepositoryException
+   //    */
+   //   private boolean isPrefixMatch(ValueFactoryImpl valueFactory, String uuid, String prefix) throws RepositoryException
+   //   {
+   //      DataManager dm = persister.getDataManager();
+   //      ItemData node = dm.getItemData(uuid);
+   //      if (node != null && node.isNode())
+   //      {
+   //         List<PropertyData> props = dm.getChildPropertiesData((NodeData)node);
+   //         for (PropertyData propertyData : props)
+   //         {
+   //            if (propertyData.getType() == PropertyType.PATH || propertyData.getType() == PropertyType.NAME)
+   //            {
+   //               for (ValueData vdata : propertyData.getValues())
+   //               {
+   //                  Value val =
+   //                     valueFactory.loadValue(((AbstractValueData)vdata).createTransientCopy(), propertyData.getType());
+   //                  if (propertyData.getType() == PropertyType.PATH)
+   //                  {
+   //                     if (isPrefixMatch(((PathValue)val).getQPath(), prefix))
+   //                        return true;
+   //                  }
+   //                  else if (propertyData.getType() == PropertyType.NAME)
+   //                  {
+   //                     if (isPrefixMatch(((NameValue)val).getQName(), prefix))
+   //                        return true;
+   //                  }
+   //               }
+   //            }
+   //         }
+   //      }
+   //      return false;
+   //   }
+   //
+   //   private boolean isPrefixMatch(QPath value, String prefix) throws NamespaceException
+   //   {
+   //      for (int i = 0; i < value.getEntries().length; i++)
+   //      {
+   //         if (isPrefixMatch(value.getEntries()[i], prefix))
+   //            return true;
+   //      }
+   //      return false;
+   //   }
+   //
+   //   private boolean isPrefixMatch(InternalQName value, String prefix) throws NamespaceException
+   //   {
+   //      return (value.getNamespace().equals(getURI(prefix)));
+   //   }
 
-   private boolean isPrefixMatch(QPath value, String prefix) throws NamespaceException
-   {
-      for (int i = 0; i < value.getEntries().length; i++)
-      {
-         if (isPrefixMatch(value.getEntries()[i], prefix))
-            return true;
-      }
-      return false;
-   }
+   //   /**
+   //    * @param query
+   //    * @return
+   //    * @throws RepositoryException
+   //    */
+   //   private Set<String> getNodes(Query query) throws RepositoryException
+   //   {
+   //      Set<String> result = new HashSet<String>();
+   //
+   //      Iterator<QueryHandler> it = queryHandlers.iterator();
+   //      try
+   //      {
+   //         while (it.hasNext())
+   //         {
+   //            QueryHandler queryHandler = it.next();
+   //            QueryHits hits = queryHandler.executeQuery(query);
+   //
+   //            ScoreNode sn;
+   //
+   //            while ((sn = hits.nextScoreNode()) != null)
+   //            {
+   //               result.add(sn.getNodeId());
+   //            }
+   //            //            for (int i = 0; i < hits.getSize(); i++)
+   //            //            {
+   //            //               result.add(hits.getFieldContent(i, FieldNames.UUID));
+   //            //            }
+   //         }
+   //      }
+   //      catch (IOException e)
+   //      {
+   //         throw new RepositoryException(e.getLocalizedMessage(), e);
+   //      }
+   //      return result;
+   //   }
 
-   private boolean isPrefixMatch(InternalQName value, String prefix) throws NamespaceException
-   {
-      return (value.getNamespace().equals(getURI(prefix)));
-   }
-
-   /**
-    * @param query
-    * @return
-    * @throws RepositoryException
-    */
-   private Set<String> getNodes(Query query) throws RepositoryException
-   {
-      Set<String> result = new HashSet<String>();
-
-      Iterator<QueryHandler> it = queryHandlers.iterator();
-      try
-      {
-         while (it.hasNext())
-         {
-            QueryHandler queryHandler = it.next();
-            QueryHits hits = queryHandler.executeQuery(query);
-
-            ScoreNode sn;
-
-            while ((sn = hits.nextScoreNode()) != null)
-            {
-               result.add(sn.getNodeId());
-            }
-            //            for (int i = 0; i < hits.getSize(); i++)
-            //            {
-            //               result.add(hits.getFieldContent(i, FieldNames.UUID));
-            //            }
-         }
-      }
-      catch (IOException e)
-      {
-         throw new RepositoryException(e.getLocalizedMessage(), e);
-      }
-      return result;
-   }
-
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/NodeTypeDataManagerImpl.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/NodeTypeDataManagerImpl.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/NodeTypeDataManagerImpl.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -51,10 +51,8 @@
 import org.exoplatform.services.jcr.impl.core.LocationFactory;
 import org.exoplatform.services.jcr.impl.core.nodetype.registration.NodeDefinitionComparator;
 import org.exoplatform.services.jcr.impl.core.nodetype.registration.PropertyDefinitionComparator;
-import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
+import org.exoplatform.services.jcr.impl.core.query.RepositoryIndexSearcherHolder;
 import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
-import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
-import org.exoplatform.services.jcr.impl.core.query.lucene.ScoreNode;
 import org.exoplatform.services.jcr.impl.core.value.BaseValue;
 import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
 import org.exoplatform.services.jcr.impl.dataflow.TransientNodeData;
@@ -78,7 +76,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -129,12 +126,15 @@
     */
    private final Map<NodeTypeManagerListener, NodeTypeManagerListener> listeners;
 
-   protected HashSet<QueryHandler> queryHandlers;
+   // protected HashSet<QueryHandler> queryHandlers;
 
    private final ValueFactoryImpl valueFactory;
 
+   protected final RepositoryIndexSearcherHolder indexSearcherHolder;
+
    public NodeTypeDataManagerImpl(RepositoryEntry config, LocationFactory locationFactory,
-      NamespaceRegistry namespaceRegistry, NodeTypeDataPersister persister) throws RepositoryException
+      NamespaceRegistry namespaceRegistry, NodeTypeDataPersister persister,
+      RepositoryIndexSearcherHolder indexSearcherHolder) throws RepositoryException
    {
 
       this.namespaceRegistry = namespaceRegistry;
@@ -142,6 +142,7 @@
       this.persister = persister;
 
       this.locationFactory = locationFactory;
+      this.indexSearcherHolder = indexSearcherHolder;
       this.valueFactory = new ValueFactoryImpl(locationFactory);
       this.accessControlPolicy = config.getAccessControl();
 
@@ -151,7 +152,7 @@
       this.listeners = Collections.synchronizedMap(new WeakHashMap<NodeTypeManagerListener, NodeTypeManagerListener>());
       this.buildInNodeTypesNames = new HashSet<InternalQName>();
       initDefault();
-      this.queryHandlers = new HashSet<QueryHandler>();
+      //this.queryHandlers = new HashSet<QueryHandler>();
    }
 
    /**
@@ -162,7 +163,8 @@
     * @throws RepositoryException
     */
    public NodeTypeDataManagerImpl(String accessControlPolicy, LocationFactory locationFactory,
-      NamespaceRegistry namespaceRegistry, NodeTypeDataPersister persister) throws RepositoryException
+      NamespaceRegistry namespaceRegistry, NodeTypeDataPersister persister,
+      RepositoryIndexSearcherHolder indexSearcherHolder) throws RepositoryException
    {
 
       this.namespaceRegistry = namespaceRegistry;
@@ -170,6 +172,7 @@
       this.persister = persister;
 
       this.locationFactory = locationFactory;
+      this.indexSearcherHolder = indexSearcherHolder;
       this.valueFactory = new ValueFactoryImpl(locationFactory);
       this.accessControlPolicy = accessControlPolicy;
 
@@ -178,7 +181,7 @@
       this.defsHolder = new ItemDefinitionDataHolder();
       this.listeners = Collections.synchronizedMap(new WeakHashMap<NodeTypeManagerListener, NodeTypeManagerListener>());
       this.buildInNodeTypesNames = new HashSet<InternalQName>();
-      this.queryHandlers = new HashSet<QueryHandler>();
+      //this.queryHandlers = new HashSet<QueryHandler>();
    }
 
    /**
@@ -195,10 +198,11 @@
       }
    }
 
-   public void addQueryHandler(QueryHandler queryHandler)
-   {
-      queryHandlers.add(queryHandler);
-   }
+   //
+   //   public void addQueryHandler(QueryHandler queryHandler)
+   //   {
+   //      queryHandlers.add(queryHandler);
+   //   }
 
    /**
     * {@inheritDoc}
@@ -393,7 +397,7 @@
     */
    public Set<String> getNodes(InternalQName nodeType) throws RepositoryException
    {
-      return getNodes(nodeType, new InternalQName[0], new InternalQName[0]);
+      return indexSearcherHolder.getNodesByNodeType(nodeType);
    }
 
    /**
@@ -407,56 +411,47 @@
    public Set<String> getNodes(InternalQName nodeType, InternalQName[] includeProperties,
       InternalQName[] excludeProperties) throws RepositoryException
    {
-      Query query = getQuery(nodeType);
-      if (includeProperties.length > 0)
-      {
-         BooleanQuery tmp = new BooleanQuery();
-         for (int i = 0; i < includeProperties.length; i++)
-         {
+      return new HashSet<String>();
 
-            String field = locationFactory.createJCRName(includeProperties[i]).getAsString();
-            tmp.add(new TermQuery(new Term(FieldNames.PROPERTIES_SET, field)), Occur.MUST);
-         }
-         tmp.add(query, Occur.MUST);
-         query = tmp;
-      }
-
-      if (excludeProperties.length > 0)
-      {
-         BooleanQuery tmp = new BooleanQuery();
-         for (int i = 0; i < excludeProperties.length; i++)
-         {
-
-            String field = locationFactory.createJCRName(excludeProperties[i]).getAsString();
-            tmp.add(new TermQuery(new Term(FieldNames.PROPERTIES_SET, field)), Occur.MUST_NOT);
-         }
-         tmp.add(query, Occur.MUST);
-         query = tmp;
-      }
-
-      Iterator<QueryHandler> it = queryHandlers.iterator();
-      Set<String> result = new HashSet<String>();
-
-      try
-      {
-         while (it.hasNext())
-         {
-            QueryHandler queryHandler = it.next();
-            QueryHits hits = queryHandler.executeQuery(query);
-
-            ScoreNode sn;
-
-            while ((sn = hits.nextScoreNode()) != null)
-            {
-               result.add(sn.getNodeId());
-            }
-         }
-      }
-      catch (IOException e)
-      {
-         throw new RepositoryException(e.getLocalizedMessage(), e);
-      }
-      return result;
+      //      Query query = getQuery(nodeType);
+      //      if (includeProperties.length > 0)
+      //      {
+      //         BooleanQuery tmp = new BooleanQuery();
+      //         for (int i = 0; i < includeProperties.length; i++)
+      //         {
+      //
+      //            String field = locationFactory.createJCRName(includeProperties[i]).getAsString();
+      //            tmp.add(new TermQuery(new Term(FieldNames.PROPERTIES_SET, field)), Occur.MUST);
+      //         }
+      //         tmp.add(query, Occur.MUST);
+      //         query = tmp;
+      //      }
+      //
+      //      if (excludeProperties.length > 0)
+      //      {
+      //         BooleanQuery tmp = new BooleanQuery();
+      //         for (int i = 0; i < excludeProperties.length; i++)
+      //         {
+      //
+      //            String field = locationFactory.createJCRName(excludeProperties[i]).getAsString();
+      //            tmp.add(new TermQuery(new Term(FieldNames.PROPERTIES_SET, field)), Occur.MUST_NOT);
+      //         }
+      //         tmp.add(query, Occur.MUST);
+      //         query = tmp;
+      //      }
+      //
+      //      Iterator<QueryHandler> it = queryHandlers.iterator();
+      //      Set<String> result = new HashSet<String>();
+      //
+      //      try
+      //      {
+      //         indexSearcherHolder.getNodesByNodeType()
+      //      }
+      //      catch (IOException e)
+      //      {
+      //         throw new RepositoryException(e.getLocalizedMessage(), e);
+      //      }
+      //      return result;
    }
 
    /**
@@ -486,11 +481,11 @@
       return propertyDefinitions;
    }
 
-   // TODO make me private
-   public Set<QueryHandler> getQueryHandlers()
-   {
-      return queryHandlers;
-   }
+   //   // TODO make me private
+   //   public Set<QueryHandler> getQueryHandlers()
+   //   {
+   //      return queryHandlers;
+   //   }
 
    /**
     * @param nodeTypeName

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/VolatileNodeTypeDataManager.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/VolatileNodeTypeDataManager.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/nodetype/VolatileNodeTypeDataManager.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -20,13 +20,11 @@
 
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeData;
 import org.exoplatform.services.jcr.datamodel.InternalQName;
-import org.exoplatform.services.jcr.impl.core.query.QueryHandler;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
 
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 
 import javax.jcr.RepositoryException;
@@ -43,9 +41,10 @@
    public VolatileNodeTypeDataManager(NodeTypeDataManagerImpl nodeTypeDataManagerImpl) throws RepositoryException
    {
       super(nodeTypeDataManagerImpl.accessControlPolicy, nodeTypeDataManagerImpl.locationFactory,
-         nodeTypeDataManagerImpl.namespaceRegistry, nodeTypeDataManagerImpl.persister);
+         nodeTypeDataManagerImpl.namespaceRegistry, nodeTypeDataManagerImpl.persister,
+         nodeTypeDataManagerImpl.indexSearcherHolder);
       this.superNodeTypeDataManager = nodeTypeDataManagerImpl;
-      this.queryHandlers = new HashSet<QueryHandler>(nodeTypeDataManagerImpl.queryHandlers);
+      //this.queryHandlers = new HashSet<QueryHandler>(nodeTypeDataManagerImpl.queryHandlers);
 
       registerVolatileNodeTypes(superNodeTypeDataManager.getAllNodeTypes());
    }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/ErrorLog.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/ErrorLog.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/ErrorLog.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -17,6 +17,9 @@
 
 package org.exoplatform.services.jcr.impl.core.query;
 
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -31,253 +34,204 @@
 import java.util.List;
 import java.util.Set;
 
-import org.exoplatform.services.log.Log;
-
-import org.exoplatform.services.log.ExoLogger;
-
 /**
- * All changes that must be in index but interrupted by IOException are here. Created by The eXo
- * Platform SAS Author : Sergey Karpenko <sergey.karpenko at exoplatform.com.ua>
+ * All changes that must be in index but interrupted by IOException are here.
+ * Created by The eXo Platform SAS Author : Sergey Karpenko
+ * <sergey.karpenko at exoplatform.com.ua>
  * 
  * @version $Id: $
  */
 
-public class ErrorLog
-{
-   public static final int DEFAULT_FILE_SIZE = 50; // Kb
+public class ErrorLog {
 
-   /**
-    * Logger instance for this class
-    */
-   private static final Log LOG = ExoLogger.getLogger(ErrorLog.class);
+    /**
+     * Logger instance for this class
+     */
+    private static final Log LOG = ExoLogger.getLogger(ErrorLog.class);
 
-   /**
-    * REMOVE term.
-    */
-   public static final String REMOVE = "rem";
+    /**
+     * REMOVE term.
+     */
+    public static final String REMOVE = "rem";
 
-   /**
-    * ADD term.
-    */
-   public static final String ADD = "add";
+    /**
+     * ADD term.
+     */
+    public static final String ADD = "add";
 
-   /**
-    * The log file
-    */
-   private final File logFile;
+    /**
+     * The log file
+     */
+    private final File logFile;
 
-   /**
-    * Writer to the log file
-    */
-   private FileChannel out;
+    /**
+     * Writer to the log file
+     */
+    private FileChannel out;
 
-   /**
-    * File size in Kb. Used on create and clear(truncate) methods.
-    */
-   private int fileSize = DEFAULT_FILE_SIZE; // Kb
+    /**
+     * File size in Kb. Used on create and clear(truncate) methods.
+     */
+    private int fileSize = 0; // Kb
 
-   /**
-    * ErrorLog constructor.
-    * 
-    * @param file
-    * @throws IOException
-    */
-   public ErrorLog(File file) throws IOException
-   {
-      logFile = file;
-      openFile(file);
-   }
+    /**
+     * ErrorLog constructor.
+     * 
+     * @param file
+     * @param errorLogSize
+     * @throws IOException
+     */
+    public ErrorLog(File file, int errorLogSize) throws IOException {
+	fileSize = errorLogSize;
+	logFile = file;
+	openFile(file);
+    }
 
-   /**
-    * ErrorLog constructor.
-    * 
-    * @param file
-    * @param errorLogSize
-    * @throws IOException
-    */
-   public ErrorLog(File file, int errorLogSize) throws IOException
-   {
-      fileSize = errorLogSize;
-      logFile = file;
-      openFile(file);
-   }
+    /**
+     * openFile.
+     * 
+     * @param log
+     * @throws IOException
+     */
+    private void openFile(File log) throws IOException {
+	// set file size;
+	if (!log.exists()) {
+	    log.getParentFile().mkdirs();
+	    log.createNewFile();
 
-   /**
-    * openFile.
-    * 
-    * @param log
-    * @throws IOException
-    */
-   private void openFile(File log) throws IOException
-   {
-      // set file size;
-      if (!log.exists())
-      {
-         log.getParentFile().mkdirs();
-         log.createNewFile();
+	    out = new FileOutputStream(log).getChannel();
+	    out.position(1024 * fileSize - 1);
+	    out.write(ByteBuffer.wrap(new byte[] { 0 }));
+	    out.position(0);
+	    out.force(false);
+	} else {
+	    out = new FileOutputStream(log, true).getChannel();
+	}
+    }
 
-         out = new FileOutputStream(log).getChannel();
-         out.position(1024 * fileSize - 1);
-         out.write(ByteBuffer.wrap(new byte[]{0}));
-         out.position(0);
-         out.force(false);
-      }
-      else
-      {
-         out = new FileOutputStream(log, true).getChannel();
-      }
-   }
+    /**
+     * Appends an action to the log.
+     * 
+     * @param action
+     *            the action to append.
+     * @throws IOException
+     *             if the node cannot be written to the redo log.
+     */
+    public void append(String action, String uuid) throws IOException {
+	initOut();
+	out.write(ByteBuffer.wrap((action + " " + uuid + "\n").getBytes()));
+    }
 
-   /**
-    * Appends an action to the log.
-    * 
-    * @param action
-    *          the action to append.
-    * @throws IOException
-    *           if the node cannot be written to the redo log.
-    */
-   public void append(String action, String uuid) throws IOException
-   {
-      initOut();
-      out.write(ByteBuffer.wrap((action + " " + uuid + "\n").getBytes()));
-   }
+    /**
+     * Flushes all pending writes to the underlying file.
+     * 
+     * @throws IOException
+     *             if an error occurs while writing.
+     */
+    public void flush() throws IOException {
+	if (out != null) {
+	    out.force(false);
+	}
+    }
 
-   /**
-    * Flushes all pending writes to the underlying file.
-    * 
-    * @throws IOException
-    *           if an error occurs while writing.
-    */
-   public void flush() throws IOException
-   {
-      if (out != null)
-      {
-         out.force(false);
-      }
-   }
+    /**
+     * Clears the redo log.
+     * 
+     * @throws IOException
+     *             if the redo log cannot be cleared.
+     */
+    public void clear() throws IOException {
+	if (out != null) {
+	    out.truncate(0);
+	    out.close();
+	    out = new FileOutputStream(logFile).getChannel();
+	    out.position(1024 * fileSize - 1);
+	    out.write(ByteBuffer.wrap(new byte[] { 0 }));
+	    out.position(0);
+	    out.force(false);
+	}
+    }
 
-   /**
-    * Clears the redo log.
-    * 
-    * @throws IOException
-    *           if the redo log cannot be cleared.
-    */
-   public void clear() throws IOException
-   {
-      if (out != null)
-      {
-         out.truncate(0);
-         out.close();
-         out = new FileOutputStream(logFile).getChannel();
-         out.position(1024 * fileSize - 1);
-         out.write(ByteBuffer.wrap(new byte[]{0}));
-         out.position(0);
-         out.force(false);
-      }
-   }
+    /**
+     * Initializes the {@link #out} stream if it is not yet set.
+     * 
+     * @throws IOException
+     *             if an error occurs while creating the output stream.
+     */
+    private void initOut() throws IOException {
+	if (out == null) {
+	    FileOutputStream os = new FileOutputStream(logFile, false);
+	    out = os.getChannel();
+	}
+    }
 
-   /**
-    * Initializes the {@link #out} stream if it is not yet set.
-    * 
-    * @throws IOException
-    *           if an error occurs while creating the output stream.
-    */
-   private void initOut() throws IOException
-   {
-      if (out == null)
-      {
-         FileOutputStream os = new FileOutputStream(logFile, false);
-         out = os.getChannel();
-      }
-   }
+    /**
+     * Reads the log file .
+     * 
+     * @throws IOException
+     *             if an error occurs while reading from the log file.
+     */
+    public List<String> readList() throws IOException {
+	InputStream in = new FileInputStream(logFile);
+	try {
+	    List<String> list = new ArrayList<String>();
+	    BufferedReader reader = new BufferedReader(
+		    new InputStreamReader(in));
+	    String line;
+	    while ((line = reader.readLine()) != null) {
+		if (!line.matches("\\x00++")) {
+		    list.add(line);
+		}
+	    }
+	    return list;
 
-   /**
-    * Reads the log file .
-    * 
-    * @throws IOException
-    *           if an error occurs while reading from the log file.
-    */
-   public List<String> readList() throws IOException
-   {
-      InputStream in = new FileInputStream(logFile);
-      try
-      {
-         List<String> list = new ArrayList<String>();
-         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-         String line;
-         while ((line = reader.readLine()) != null)
-         {
-            if (!line.matches("\\x00++"))
-            {
-               list.add(line);
-            }
-         }
-         return list;
+	} finally {
+	    if (in != null) {
+		try {
+		    in.close();
+		} catch (IOException e) {
+		    LOG.warn("Exception while closing error log: "
+			    + e.toString());
+		}
+	    }
+	}
+    }
 
-      }
-      finally
-      {
-         if (in != null)
-         {
-            try
-            {
-               in.close();
-            }
-            catch (IOException e)
-            {
-               LOG.warn("Exception while closing error log: " + e.toString());
-            }
-         }
-      }
-   }
+    public void readChanges(Set<String> rem, Set<String> add)
+	    throws IOException {
+	List<String> list = readList();
 
-   public void readChanges(Set<String> rem, Set<String> add) throws IOException
-   {
-      List<String> list = readList();
+	Iterator<String> it = list.iterator();
+	while (it.hasNext()) {
+	    String[] str = it.next().split(" ");
+	    if (str.length == 2) {
+		if (str[0].equals(ADD)) {
+		    add.add(str[1]);
+		} else if (str[0].equals(REMOVE)) {
+		    rem.add(str[1]);
+		}
+	    }
+	}
+    }
 
-      Iterator<String> it = list.iterator();
-      while (it.hasNext())
-      {
-         String[] str = it.next().split(" ");
-         if (str.length == 2)
-         {
-            if (str[0].equals(ADD))
-            {
-               add.add(str[1]);
-            }
-            else if (str[0].equals(REMOVE))
-            {
-               rem.add(str[1]);
-            }
-         }
-      }
-   }
+    public void writeChanges(Set<String> removed, Set<String> added)
+	    throws IOException {
+	try {
+	    if (!removed.isEmpty()) {
+		Iterator<String> rem = removed.iterator();
+		while (rem.hasNext()) {
+		    append(ErrorLog.REMOVE, rem.next());
+		}
+	    }
+	    if (!added.isEmpty()) {
+		Iterator<String> add = added.iterator();
+		while (add.hasNext()) {
+		    append(ErrorLog.ADD, add.next());
+		}
+	    }
+	} finally {
+	    flush();
+	}
+    }
 
-   public void writeChanges(Set<String> removed, Set<String> added) throws IOException
-   {
-      try
-      {
-         if (!removed.isEmpty())
-         {
-            Iterator<String> rem = removed.iterator();
-            while (rem.hasNext())
-            {
-               append(ErrorLog.REMOVE, rem.next());
-            }
-         }
-         if (!added.isEmpty())
-         {
-            Iterator<String> add = added.iterator();
-            while (add.hasNext())
-            {
-               append(ErrorLog.ADD, add.next());
-            }
-         }
-      }
-      finally
-      {
-         flush();
-      }
-   }
-
 }

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexException.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexException.java	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexException.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * 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 org.exoplatform.services.jcr.impl.core.query;
+
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ * 
+ * @author <a href="mailto:Sergey.Kabashnyuk at gmail.com">Sergey Kabashnyuk</a>
+ * @version $Id: $
+ */
+public class IndexException extends RepositoryException
+{
+   /**
+    * 
+    */
+   private static final long serialVersionUID = 2247843831064852072L;
+
+   /**
+    * Class logger.
+    */
+   private static final Log LOG = ExoLogger.getLogger(IndexException.class);
+
+   /**
+    * 
+    */
+   public IndexException()
+   {
+      super();
+   }
+
+   /**
+    * @param message
+    * @param cause
+    */
+   public IndexException(String message, Throwable cause)
+   {
+      super(message, cause);
+   }
+
+   /**
+    * @param message
+    */
+   public IndexException(String message)
+   {
+      super(message);
+   }
+
+   /**
+    * @param cause
+    */
+   public IndexException(Throwable cause)
+   {
+      super(cause);
+   }
+}


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/IndexException.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/QueryHandlerContext.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -21,6 +21,7 @@
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
 import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeDataManagerImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.LuceneVirtualTableResolver;
 
 /**
  * Acts as an argument for the {@link QueryHandler} to keep the interface
@@ -68,6 +69,8 @@
 
     private final boolean createInitialIndex;
 
+    private final LuceneVirtualTableResolver virtualTableResolver;
+
     /**
      * Creates a new context instance.
      * 
@@ -86,6 +89,7 @@
      * @param parentHandler
      *            the parent query handler or <code>null</code> it there is no
      *            parent handler.
+     * @param virtualTableResolver
      * @param excludedNodeId
      *            id of the node that should be excluded from indexing. Any
      *            descendant of that node is also excluded from indexing.
@@ -94,7 +98,8 @@
 	    IndexingTree indexingTree, NodeTypeDataManager nodeTypeDataManager,
 	    NamespaceRegistryImpl nsRegistry, QueryHandler parentHandler,
 	    String indexDirectory, DocumentReaderService extractor,
-	    boolean createInitialIndex) {
+	    boolean createInitialIndex,
+	    LuceneVirtualTableResolver virtualTableResolver) {
 	this.stateMgr = stateMgr;
 	this.indexingTree = indexingTree;
 	this.nodeTypeDataManager = nodeTypeDataManager;
@@ -102,6 +107,7 @@
 	this.indexDirectory = indexDirectory;
 	this.extractor = extractor;
 	this.createInitialIndex = createInitialIndex;
+	this.virtualTableResolver = virtualTableResolver;
 	this.propRegistry = new PropertyTypeRegistry(nodeTypeDataManager);
 	this.parentHandler = parentHandler;
 	((NodeTypeDataManagerImpl) this.nodeTypeDataManager)
@@ -109,6 +115,13 @@
     }
 
     /**
+     * @return the virtualTableResolver
+     */
+    public LuceneVirtualTableResolver getVirtualTableResolver() {
+	return virtualTableResolver;
+    }
+
+    /**
      * @return the createInitialIndex
      */
     public boolean isCreateInitialIndex() {

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/RepositoryIndexSearcherHolder.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/RepositoryIndexSearcherHolder.java	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/RepositoryIndexSearcherHolder.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * 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 org.exoplatform.services.jcr.impl.core.query;
+
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.picocontainer.Startable;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Created by The eXo Platform SAS.
+ * 
+ * @author <a href="mailto:Sergey.Kabashnyuk at gmail.com">Sergey Kabashnyuk</a>
+ * @version $Id: $
+ */
+public class RepositoryIndexSearcherHolder implements Startable {
+    private final List<SearchManager> indexSearchers;
+
+    /**
+     * Class logger.
+     */
+    private final Log log = ExoLogger
+	    .getLogger(RepositoryIndexSearcherHolder.class);
+
+    /**
+     * @param indexSearchers
+     */
+    public RepositoryIndexSearcherHolder() {
+	super();
+	this.indexSearchers = new ArrayList<SearchManager>();
+    }
+
+    /**
+     * @return the indexSearchers
+     */
+    public void addIndexSearcher(final SearchManager indexSearcher) {
+	this.indexSearchers.add(indexSearcher);
+    }
+
+    /**
+     * @return
+     * @throws IndexException
+     */
+    public Set<String> getFieldNames() throws IndexException {
+	final Set<String> fildsSet = new HashSet<String>();
+
+	for (final SearchManager queryHandler : this.indexSearchers) {
+
+	    fildsSet.addAll(queryHandler.getFieldNames());
+	}
+	return fildsSet;
+    }
+
+    public Set<String> getNodesByNodeType(final InternalQName nodeType)
+	    throws RepositoryException {
+	final Set<String> result = new HashSet<String>();
+	for (final SearchManager indexingService : this.indexSearchers) {
+	    result.addAll(indexingService.getNodesByNodeType(nodeType));
+	}
+
+	return result;
+    }
+
+    /**
+     * @param uri
+     * @return
+     * @throws RepositoryException
+     */
+    public Set<String> getNodesByUri(final String uri)
+	    throws RepositoryException {
+	final Set<String> result = new HashSet<String>();
+	for (final SearchManager indexingService : this.indexSearchers) {
+	    result.addAll(indexingService.getNodesByUri(uri));
+	}
+
+	return result;
+    }
+
+    /**
+     * @return the indexSearchers
+     */
+    public void removeIndexSearcher(final SearchManager indexSearcher) {
+	this.indexSearchers.remove(indexSearcher);
+    }
+
+    public void start() {
+    }
+
+    public void stop() {
+	this.indexSearchers.clear();
+    }
+}


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/RepositoryIndexSearcherHolder.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchIndexConfigurationHelper.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -19,7 +19,9 @@
 package org.exoplatform.services.jcr.impl.core.query;
 
 import org.exoplatform.services.jcr.config.QueryHandlerEntry;
+import org.exoplatform.services.jcr.config.QueryHandlerParams;
 import org.exoplatform.services.jcr.config.RepositoryConfigurationException;
+import org.exoplatform.services.jcr.config.SimpleParameterEntry;
 import org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex;
 
 import java.io.IOException;
@@ -42,9 +44,93 @@
 	this.searchIndex = searchIndex;
     }
 
+    /**
+     * Initialize parameters
+     * 
+     * @param queryHandlerEntry
+     * @throws IOException
+     * @throws RepositoryConfigurationException
+     */
     public void init(QueryHandlerEntry queryHandlerEntry) throws IOException,
 	    RepositoryConfigurationException {
 	// Path will be set using queryHandelContext
 
+	for (SimpleParameterEntry parameter : queryHandlerEntry.getParameters()) {
+	    setParam(parameter.getName(), parameter.getValue());
+	}
+
     }
+
+    /**
+     * @param name
+     * @param value
+     */
+    private void setParam(String name, String value) {
+
+	if (QueryHandlerParams.PARAM_AUTO_REPAIR.equals(name))
+	    searchIndex.setAutoRepair(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_BUFFER_SIZE.equals(name))
+	    searchIndex.setBufferSize(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_CACHE_SIZE.equals(name))
+	    searchIndex.setCacheSize(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_CONSISTENCY_CHECK_ENABLED
+		.equals(name))
+	    searchIndex.setEnableConsistencyCheck(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_DOCUMENT_ORDER.equals(name))
+	    searchIndex.setRespectDocumentOrder(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_EXCERPTPROVIDER_CLASS.equals(name))
+	    searchIndex.setExcerptProviderClass(value);
+	// else if
+	// (QueryHandlerParams.PARAM_EXCLUDED_NODE_IDENTIFERS.equals(name))
+	// searchIndex.setE
+	else if (QueryHandlerParams.PARAM_EXTRACTOR_BACKLOG.equals(name))
+	    searchIndex.setExtractorBackLogSize(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_EXTRACTOR_POOLSIZE.equals(name))
+	    searchIndex.setExtractorPoolSize(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_EXTRACTOR_TIMEOUT.equals(name))
+	    searchIndex.setExtractorTimeout(Long.parseLong(value));
+	else if (QueryHandlerParams.PARAM_FORCE_CONSISTENCYCHECK.equals(name))
+	    searchIndex.setForceConsistencyCheck(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_ERRORLOG_SIZE.equals(name))
+	    searchIndex.setErrorLogfileSize(Integer.parseInt(value));
+	// else if (QueryHandlerParams.PARAM_INDEX_DIR.equals(name))
+	// searchIndex.setBufferSize(0);
+	// else if (OLD_PARAM_INDEX_DIR
+	else if (QueryHandlerParams.PARAM_INDEXING_CONFIGURATION_PATH
+		.equals(name))
+	    searchIndex.setIndexingConfiguration(value);
+	else if (QueryHandlerParams.PARAM_INDEXING_CONFIGURATION_CLASS
+		.equals(name))
+	    searchIndex.setIndexingConfigurationClass(value);
+	else if (QueryHandlerParams.PARAM_MAX_FIELD_LENGTH.equals(name))
+	    searchIndex.setMaxFieldLength(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_MAX_MERGE_DOCS.equals(name))
+	    searchIndex.setMaxMergeDocs(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_MERGE_FACTOR.equals(name))
+	    searchIndex.setMergeFactor(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_MIN_MERGE_DOCS.equals(name))
+	    searchIndex.setMinMergeDocs(Integer.parseInt(value));
+	else if (QueryHandlerParams.PARAM_QUERY_CLASS.equals(name))
+	    searchIndex.setQueryClass(value);
+	else if (QueryHandlerParams.PARAM_RESULT_FETCH_SIZE.equals(name))
+	    searchIndex.setResultFetchSize(Integer.parseInt(value));
+	// else if (QueryHandlerParams.PARAM_ROOT_NODE_ID.equals(name))
+	// searchIndex.setBufferSize(0);
+	else if (QueryHandlerParams.PARAM_SPELLCHECKER_CLASS.equals(name))
+	    searchIndex.setSpellCheckerClass(value);
+	else if (QueryHandlerParams.PARAM_SUPPORT_HIGHLIGHTING.equals(name))
+	    searchIndex.setSupportHighlighting(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_SYNONYMPROVIDER_CLASS.equals(name))
+	    searchIndex.setSynonymProviderClass(value);
+	else if (QueryHandlerParams.PARAM_SYNONYMPROVIDER_CONFIG_PATH
+		.equals(name))
+	    searchIndex.setSynonymProviderConfigPath(value);
+	else if (QueryHandlerParams.PARAM_USE_COMPOUNDFILE.equals(name))
+	    searchIndex.setUseCompoundFile(Boolean.parseBoolean(value));
+	else if (QueryHandlerParams.PARAM_VOLATILE_IDLE_TIME.equals(name))
+	    searchIndex.setVolatileIdleTime(Integer.parseInt(value));
+	// else if (QueryHandlerParams.PARAM_UPGRADE_INDEX.equals(name))
+	// searchIndex.i
+
+    }
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SearchManager.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,6 +16,11 @@
  */
 package org.exoplatform.services.jcr.impl.core.query;
 
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.WildcardQuery;
+import org.apache.lucene.search.BooleanClause.Occur;
 import org.exoplatform.container.configuration.ConfigurationManager;
 import org.exoplatform.services.document.DocumentReaderService;
 import org.exoplatform.services.jcr.config.QueryHandlerEntry;
@@ -26,13 +31,26 @@
 import org.exoplatform.services.jcr.dataflow.ItemState;
 import org.exoplatform.services.jcr.dataflow.ItemStateChangesLog;
 import org.exoplatform.services.jcr.dataflow.persistent.MandatoryItemsPersistenceListener;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
 import org.exoplatform.services.jcr.datamodel.ItemData;
 import org.exoplatform.services.jcr.datamodel.NodeData;
+import org.exoplatform.services.jcr.datamodel.PropertyData;
 import org.exoplatform.services.jcr.datamodel.QPath;
+import org.exoplatform.services.jcr.datamodel.ValueData;
 import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.LocationFactory;
 import org.exoplatform.services.jcr.impl.core.NamespaceRegistryImpl;
 import org.exoplatform.services.jcr.impl.core.SessionDataManager;
 import org.exoplatform.services.jcr.impl.core.SessionImpl;
+import org.exoplatform.services.jcr.impl.core.query.lucene.FieldNames;
+import org.exoplatform.services.jcr.impl.core.query.lucene.LuceneVirtualTableResolver;
+import org.exoplatform.services.jcr.impl.core.query.lucene.QueryHits;
+import org.exoplatform.services.jcr.impl.core.query.lucene.ScoreNode;
+import org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex;
+import org.exoplatform.services.jcr.impl.core.value.NameValue;
+import org.exoplatform.services.jcr.impl.core.value.PathValue;
+import org.exoplatform.services.jcr.impl.core.value.ValueFactoryImpl;
+import org.exoplatform.services.jcr.impl.dataflow.AbstractValueData;
 import org.exoplatform.services.jcr.impl.dataflow.persistent.WorkspacePersistentDataManager;
 import org.exoplatform.services.log.ExoLogger;
 import org.exoplatform.services.log.Log;
@@ -42,6 +60,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -52,7 +71,9 @@
 import java.util.StringTokenizer;
 
 import javax.jcr.Node;
+import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
+import javax.jcr.Value;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.query.Query;
 
@@ -108,6 +129,8 @@
 
     private final ConfigurationManager cfm;
 
+    protected LuceneVirtualTableResolver virtualTableResolver;
+
     /**
      * Creates a new <code>SearchManager</code>.
      * 
@@ -134,17 +157,19 @@
     public SearchManager(QueryHandlerEntry config, NamespaceRegistryImpl nsReg,
 	    NodeTypeDataManager ntReg, WorkspacePersistentDataManager itemMgr,
 	    SystemSearchManagerHolder parentSearchManager,
-	    DocumentReaderService extractor, ConfigurationManager cfm)
+	    DocumentReaderService extractor, ConfigurationManager cfm,
+	    final RepositoryIndexSearcherHolder indexSearcherHolder)
 	    throws RepositoryException, RepositoryConfigurationException {
 
 	this.extractor = extractor;
-
+	indexSearcherHolder.addIndexSearcher(this);
 	this.config = new QueryHandlerEntryWrapper(config);
 	this.nodeTypeDataManager = ntReg;
 	this.nsReg = nsReg;
 	this.itemMgr = itemMgr;
 	this.cfm = cfm;
-
+	this.virtualTableResolver = new LuceneVirtualTableResolver(
+		nodeTypeDataManager, nsReg);
 	this.parentSearchManager = parentSearchManager != null ? parentSearchManager
 		.get()
 		: null;
@@ -465,7 +490,7 @@
 
 	QueryHandlerContext context = new QueryHandlerContext(itemMgr,
 		indexingTree, nodeTypeDataManager, nsReg, parentHandler, config
-			.getIndexDir(), extractor, true);
+			.getIndexDir(), extractor, true, virtualTableResolver);
 	return context;
     }
 
@@ -543,4 +568,178 @@
 	}
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public Set<String> getFieldNames() throws IndexException {
+	final Set<String> fildsSet = new HashSet<String>();
+	if (handler instanceof SearchIndex) {
+	    IndexReader reader = null;
+	    try {
+		reader = ((SearchIndex) handler).getIndexReader();
+		final Collection fields = reader
+			.getFieldNames(IndexReader.FieldOption.ALL);
+		for (final Object field : fields) {
+		    fildsSet.add((String) field);
+		}
+	    } catch (IOException e) {
+		throw new IndexException(e.getLocalizedMessage(), e);
+	    } finally {
+		try {
+		    if (reader != null)
+			reader.close();
+		} catch (IOException e) {
+		    throw new IndexException(e.getLocalizedMessage(), e);
+		}
+	    }
+
+	}
+	return fildsSet;
+    }
+
+    public Set<String> getNodesByNodeType(final InternalQName nodeType)
+	    throws RepositoryException {
+
+	return getNodes(virtualTableResolver.resolve(nodeType, true));
+    }
+
+    /**
+     * Return set of uuid of nodes. Contains in names prefixes maped to the
+     * given uri
+     * 
+     * @param prefix
+     * @return
+     * @throws RepositoryException
+     */
+    public Set<String> getNodesByUri(final String uri)
+	    throws RepositoryException {
+	Set<String> result;
+	final int defaultClauseCount = BooleanQuery.getMaxClauseCount();
+	try {
+
+	    // final LocationFactory locationFactory = new
+	    // LocationFactory(this);
+	    final ValueFactoryImpl valueFactory = new ValueFactoryImpl(
+		    new LocationFactory(nsReg));
+	    BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);
+	    BooleanQuery query = new BooleanQuery();
+
+	    final String prefix = nsReg.getNamespacePrefixByURI(uri);
+	    query.add(new WildcardQuery(new Term(FieldNames.LABEL, prefix
+		    + ":*")), Occur.SHOULD);
+	    // name of the property
+	    query.add(new WildcardQuery(new Term(FieldNames.PROPERTIES_SET,
+		    prefix + ":*")), Occur.SHOULD);
+
+	    result = getNodes(query);
+
+	    // value of the property
+
+	    try {
+		final Set<String> props = getFieldNames();
+
+		query = new BooleanQuery();
+		for (final String fieldName : props) {
+		    if (!FieldNames.PROPERTIES_SET.equals(fieldName)) {
+			query.add(new WildcardQuery(new Term(fieldName, "*"
+				+ prefix + ":*")), Occur.SHOULD);
+		    }
+		}
+	    } catch (final IndexException e) {
+		throw new RepositoryException(e.getLocalizedMessage(), e);
+	    }
+
+	    final Set<String> propSet = getNodes(query);
+	    // Manually check property values;
+	    for (final String uuid : propSet) {
+		if (isPrefixMatch(valueFactory, uuid, prefix)) {
+		    result.add(uuid);
+		}
+	    }
+	} finally {
+	    BooleanQuery.setMaxClauseCount(defaultClauseCount);
+	}
+
+	return result;
+    }
+
+    private boolean isPrefixMatch(final InternalQName value, final String prefix)
+	    throws RepositoryException {
+	return value.getNamespace().equals(
+		nsReg.getNamespaceURIByPrefix(prefix));
+    }
+
+    private boolean isPrefixMatch(final QPath value, final String prefix)
+	    throws RepositoryException {
+	for (int i = 0; i < value.getEntries().length; i++) {
+	    if (isPrefixMatch(value.getEntries()[i], prefix)) {
+		return true;
+	    }
+	}
+	return false;
+    }
+
+    /**
+     * @param valueFactory
+     * @param dm
+     * @param uuid
+     * @param prefix
+     * @throws RepositoryException
+     */
+    private boolean isPrefixMatch(final ValueFactoryImpl valueFactory,
+	    final String uuid, final String prefix) throws RepositoryException {
+
+	final ItemData node = itemMgr.getItemData(uuid);
+	if (node != null && node.isNode()) {
+	    final List<PropertyData> props = itemMgr
+		    .getChildPropertiesData((NodeData) node);
+	    for (final PropertyData propertyData : props) {
+		if (propertyData.getType() == PropertyType.PATH
+			|| propertyData.getType() == PropertyType.NAME) {
+		    for (final ValueData vdata : propertyData.getValues()) {
+			final Value val = valueFactory.loadValue(
+				((AbstractValueData) vdata)
+					.createTransientCopy(), propertyData
+					.getType());
+			if (propertyData.getType() == PropertyType.PATH) {
+			    if (isPrefixMatch(((PathValue) val).getQPath(),
+				    prefix)) {
+				return true;
+			    }
+			} else if (propertyData.getType() == PropertyType.NAME) {
+			    if (isPrefixMatch(((NameValue) val).getQName(),
+				    prefix)) {
+				return true;
+			    }
+			}
+		    }
+		}
+	    }
+	}
+	return false;
+    }
+
+    /**
+     * @param query
+     * @return
+     * @throws RepositoryException
+     */
+    private Set<String> getNodes(final org.apache.lucene.search.Query query)
+	    throws RepositoryException {
+	Set<String> result = new HashSet<String>();
+	try {
+	    QueryHits hits = handler.executeQuery(query);
+
+	    ScoreNode sn;
+
+	    while ((sn = hits.nextScoreNode()) != null) {
+		// Node node = session.getNodeById(sn.getNodeId());
+		result.add(sn.getNodeId());
+	    }
+	} catch (IOException e) {
+	    throw new RepositoryException(e.getLocalizedMessage(), e);
+	}
+	return result;
+    }
+
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/SystemSearchManager.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -64,9 +64,11 @@
     public SystemSearchManager(QueryHandlerEntry config,
 	    NamespaceRegistryImpl nsReg, NodeTypeDataManager ntReg,
 	    WorkspacePersistentDataManager itemMgr,
-	    DocumentReaderService service, ConfigurationManager cfm)
+	    DocumentReaderService service, ConfigurationManager cfm,
+	    RepositoryIndexSearcherHolder indexSearcherHolder)
 	    throws RepositoryException, RepositoryConfigurationException {
-	super(config, nsReg, ntReg, itemMgr, null, service, cfm);
+	super(config, nsReg, ntReg, itemMgr, null, service, cfm,
+		indexSearcherHolder);
     }
 
     @Override
@@ -124,7 +126,7 @@
 			.getIndexDir()
 			+ "_" + INDEX_DIR_SUFFIX, extractor, changesLogBuffer
 			.size() > 0
-			&& !isStarted);
+			&& !isStarted, virtualTableResolver);
 	return context;
     }
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationEntityResolver.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationEntityResolver.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationEntityResolver.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,16 +16,16 @@
  */
 package org.exoplatform.services.jcr.impl.core.query.lucene;
 
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
 /**
  * <code>IndexingConfigurationEntityResolver</code> implements an entity
  * resolver for the indexing configuration DTD.
@@ -35,34 +35,37 @@
     /**
      * Maps system ids to DTD resource names.
      */
-    private static final Map SYSTEM_IDS;
+    private static final Map<String, String> SYSTEM_IDS;
 
     static {
-        Map systemIds = new HashMap();
-        systemIds.put(
-                "http://jackrabbit.apache.org/dtd/indexing-configuration-1.0.dtd",
-                "indexing-configuration-1.0.dtd");
-        systemIds.put(
-                "http://jackrabbit.apache.org/dtd/indexing-configuration-1.1.dtd",
-                "indexing-configuration-1.1.dtd");
-        systemIds.put(
-                "http://jackrabbit.apache.org/dtd/indexing-configuration-1.2.dtd",
-                "indexing-configuration-1.2.dtd");
-        SYSTEM_IDS = Collections.unmodifiableMap(systemIds);
+	Map<String, String> systemIds = new HashMap<String, String>();
+	systemIds
+		.put(
+			"http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd",
+			"indexing-configuration-1.0.dtd");
+	systemIds
+		.put(
+			"http://www.exoplatform.org/dtd/indexing-configuration-1.1.dtd",
+			"indexing-configuration-1.1.dtd");
+	systemIds
+		.put(
+			"http://www.exoplatform.org/dtd/indexing-configuration-1.2.dtd",
+			"indexing-configuration-1.2.dtd");
+	SYSTEM_IDS = Collections.unmodifiableMap(systemIds);
     }
 
     /**
      * {@inheritDoc}
      */
     public InputSource resolveEntity(String publicId, String systemId)
-            throws SAXException, IOException {
-        String resourceName = (String) SYSTEM_IDS.get(systemId);
-        if (resourceName != null) {
-            InputStream in = getClass().getResourceAsStream(resourceName);
-            if (in != null) {
-                return new InputSource(in);
-            }
-        }
-        return null;
+	    throws SAXException, IOException {
+	String resourceName = SYSTEM_IDS.get(systemId);
+	if (resourceName != null) {
+	    InputStream in = getClass().getResourceAsStream(resourceName);
+	    if (in != null) {
+		return new InputSource(in);
+	    }
+	}
+	return null;
     }
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationImpl.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationImpl.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/IndexingConfigurationImpl.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,22 +16,6 @@
  */
 package org.exoplatform.services.jcr.impl.core.query.lucene;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Properties;
-
-import javax.jcr.NamespaceException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-
-import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
 import org.apache.lucene.analysis.Analyzer;
 import org.exoplatform.services.jcr.core.NamespaceAccessor;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeData;
@@ -49,7 +33,6 @@
 import org.exoplatform.services.jcr.impl.core.query.AdditionalNamespaceResolver;
 import org.exoplatform.services.jcr.impl.core.query.QueryHandlerContext;
 import org.exoplatform.services.jcr.impl.core.query.misc.Pattern;
-
 import org.exoplatform.services.jcr.impl.util.ISO9075;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,1088 +43,1038 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
 /**
  * <code>IndexingConfigurationImpl</code> implements a concrete indexing
  * configuration.
  */
-public class IndexingConfigurationImpl implements IndexingConfiguration
-{
+public class IndexingConfigurationImpl implements IndexingConfiguration {
 
-   /**
-    * The logger instance for this class
-    */
-   private static final Logger log = LoggerFactory.getLogger(IndexingConfigurationImpl.class);
+    /**
+     * The logger instance for this class
+     */
+    private static final Logger log = LoggerFactory
+	    .getLogger(IndexingConfigurationImpl.class);
 
-   /**
-    * The path factory instance.
-    */
-   //private static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();
-   /**
-    * A namespace resolver for parsing QNames in the configuration.
-    */
-   private LocationFactory resolver;
+    /**
+     * The path factory instance.
+     */
+    // private static final PathFactory PATH_FACTORY =
+    // PathFactoryImpl.getInstance();
+    /**
+     * A namespace resolver for parsing QNames in the configuration.
+     */
+    private LocationFactory resolver;
 
-   /**
-    * The item state manager to retrieve additional item states.
-    */
-   private ItemDataConsumer ism;
+    /**
+     * The item state manager to retrieve additional item states.
+     */
+    private ItemDataConsumer ism;
 
-   /**
-    * A hierarchy resolver for the item state manager.
-    */
-   //   private HierarchyManager hmgr;
-   /**
-    * The {@link IndexingRule}s inside this configuration.
-    */
-   private Map configElements = new HashMap();
+    /**
+     * A hierarchy resolver for the item state manager.
+     */
+    // private HierarchyManager hmgr;
+    /**
+     * The {@link IndexingRule}s inside this configuration.
+     */
+    private Map<InternalQName, List<IndexingRule>> configElements = new HashMap<InternalQName, List<IndexingRule>>();
 
-   /**
-    * The indexing aggregates inside this configuration.
-    */
-   private AggregateRule[] aggregateRules;
+    /**
+     * The indexing aggregates inside this configuration.
+     */
+    private AggregateRule[] aggregateRules;
 
-   /**
-    * The configured analyzers for indexing properties.
-    */
-   private Map analyzers = new HashMap();
+    /**
+     * The configured analyzers for indexing properties.
+     */
+    private Map<String, Analyzer> analyzers = new HashMap<String, Analyzer>();
 
-   /**
-    * {@inheritDoc}
-    */
-   public void init(Element config, QueryHandlerContext context, NamespaceMappings nsMappings) throws Exception
-   {
-      ism = context.getItemStateManager();
+    /**
+     * {@inheritDoc}
+     */
+    public void init(Element config, QueryHandlerContext context,
+	    NamespaceMappings nsMappings) throws Exception {
+	ism = context.getItemStateManager();
 
-      NamespaceAccessor nsResolver = new AdditionalNamespaceResolver(getNamespaces(config));
-      resolver = new LocationFactory(nsResolver);//new ParsingNameResolver(NameFactoryImpl.getInstance(), nsResolver);
+	NamespaceAccessor nsResolver = new AdditionalNamespaceResolver(
+		getNamespaces(config));
+	resolver = new LocationFactory(nsResolver);// new
+	// ParsingNameResolver(NameFactoryImpl.getInstance(),
+	// nsResolver);
 
-      NodeTypeDataManager ntReg = context.getNodeTypeDataManager();
-      List<NodeTypeData> ntNames = ntReg.getAllNodeTypes();
-      List idxAggregates = new ArrayList();
-      NodeList indexingConfigs = config.getChildNodes();
-      for (int i = 0; i < indexingConfigs.getLength(); i++)
-      {
-         Node configNode = indexingConfigs.item(i);
-         if (configNode.getNodeName().equals("index-rule"))
-         {
-            IndexingRule element = new IndexingRule(configNode);
-            // register under node type and all its sub types
-            log.debug("Found rule '{}' for NodeType '{}'", element, element.getNodeTypeName());
-            for (NodeTypeData nodeTypeData : ntNames)
-            {
+	NodeTypeDataManager ntReg = context.getNodeTypeDataManager();
+	List<NodeTypeData> ntNames = ntReg.getAllNodeTypes();
+	List<AggregateRuleImpl> idxAggregates = new ArrayList<AggregateRuleImpl>();
+	NodeList indexingConfigs = config.getChildNodes();
+	for (int i = 0; i < indexingConfigs.getLength(); i++) {
+	    Node configNode = indexingConfigs.item(i);
+	    if (configNode.getNodeName().equals("index-rule")) {
+		IndexingRule element = new IndexingRule(configNode);
+		// register under node type and all its sub types
+		log.debug("Found rule '{}' for NodeType '{}'", element, element
+			.getNodeTypeName());
+		for (NodeTypeData nodeTypeData : ntNames) {
 
-               if (ntReg.isNodeType(element.getNodeTypeName(), nodeTypeData.getName()))
-               {
-                  List perNtConfig = (List)configElements.get(nodeTypeData);
-                  if (perNtConfig == null)
-                  {
-                     perNtConfig = new ArrayList();
-                     configElements.put(nodeTypeData, perNtConfig);
-                  }
-                  log.debug("Registering it for name '{}'", nodeTypeData);
-                  perNtConfig.add(new IndexingRule(element, nodeTypeData.getName()));
-               }
-            }
-         }
-         else if (configNode.getNodeName().equals("aggregate"))
-         {
-            idxAggregates.add(new AggregateRuleImpl(configNode, resolver, ism));
-         }
-         else if (configNode.getNodeName().equals("analyzers"))
-         {
-            NodeList childNodes = configNode.getChildNodes();
-            for (int j = 0; j < childNodes.getLength(); j++)
-            {
-               Node analyzerNode = childNodes.item(j);
-               if (analyzerNode.getNodeName().equals("analyzer"))
-               {
-                  String analyzerClassName = analyzerNode.getAttributes().getNamedItem("class").getNodeValue();
-                  try
-                  {
-                     Class clazz = Class.forName(analyzerClassName);
-                     if (clazz == JcrStandartAnalyzer.class)
-                     {
-                        log.warn("Not allowed to configure " + JcrStandartAnalyzer.class.getName()
-                           + " for a property. " + "Using default analyzer for that property.");
-                     }
-                     else if (Analyzer.class.isAssignableFrom(clazz))
-                     {
-                        Analyzer analyzer = (Analyzer)clazz.newInstance();
-                        NodeList propertyChildNodes = analyzerNode.getChildNodes();
-                        for (int k = 0; k < propertyChildNodes.getLength(); k++)
-                        {
-                           Node propertyNode = propertyChildNodes.item(k);
-                           if (propertyNode.getNodeName().equals("property"))
-                           {
-                              // get property name
-                              InternalQName propName =
-                                 resolver.parseJCRName(getTextContent(propertyNode)).getInternalName();
-                              String fieldName = nsMappings.translateName(propName);
-                              // set analyzer for the fulltext property fieldname
-                              int idx = fieldName.indexOf(':');
-                              fieldName =
-                                 fieldName.substring(0, idx + 1) + FieldNames.FULLTEXT_PREFIX
-                                    + fieldName.substring(idx + 1);
-                              Object prevAnalyzer = analyzers.put(fieldName, analyzer);
-                              if (prevAnalyzer != null)
-                              {
-                                 log.warn("Property " + propName.getName()
-                                    + " has been configured for multiple analyzers. "
-                                    + " Last configured analyzer is used");
-                              }
-                           }
-                        }
-                     }
-                     else
-                     {
-                        log.warn("org.apache.lucene.analysis.Analyzer is not a superclass of " + analyzerClassName
-                           + ". Ignoring this configure analyzer");
-                     }
-                  }
-                  catch (ClassNotFoundException e)
-                  {
-                     log.warn("Analyzer class not found: " + analyzerClassName, e);
-                  }
-               }
-            }
-         }
+		    if (ntReg.isNodeType(element.getNodeTypeName(),
+			    nodeTypeData.getName())) {
+			List<IndexingRule> perNtConfig = configElements
+				.get(nodeTypeData);
+			if (perNtConfig == null) {
+			    perNtConfig = new ArrayList<IndexingRule>();
+			    configElements.put(nodeTypeData.getName(),
+				    perNtConfig);
+			}
+			log.debug("Registering it for name '{}'", nodeTypeData);
+			perNtConfig.add(new IndexingRule(element, nodeTypeData
+				.getName()));
+		    }
+		}
+	    } else if (configNode.getNodeName().equals("aggregate")) {
+		idxAggregates.add(new AggregateRuleImpl(configNode, resolver,
+			ism));
+	    } else if (configNode.getNodeName().equals("analyzers")) {
+		NodeList childNodes = configNode.getChildNodes();
+		for (int j = 0; j < childNodes.getLength(); j++) {
+		    Node analyzerNode = childNodes.item(j);
+		    if (analyzerNode.getNodeName().equals("analyzer")) {
+			String analyzerClassName = analyzerNode.getAttributes()
+				.getNamedItem("class").getNodeValue();
+			try {
+			    Class clazz = Class.forName(analyzerClassName);
+			    if (clazz == JcrStandartAnalyzer.class) {
+				log
+					.warn("Not allowed to configure "
+						+ JcrStandartAnalyzer.class
+							.getName()
+						+ " for a property. "
+						+ "Using default analyzer for that property.");
+			    } else if (Analyzer.class.isAssignableFrom(clazz)) {
+				Analyzer analyzer = (Analyzer) clazz
+					.newInstance();
+				NodeList propertyChildNodes = analyzerNode
+					.getChildNodes();
+				for (int k = 0; k < propertyChildNodes
+					.getLength(); k++) {
+				    Node propertyNode = propertyChildNodes
+					    .item(k);
+				    if (propertyNode.getNodeName().equals(
+					    "property")) {
+					// get property name
+					InternalQName propName = resolver
+						.parseJCRName(
+							getTextContent(propertyNode))
+						.getInternalName();
+					String fieldName = nsMappings
+						.translateName(propName);
+					// set analyzer for the fulltext
+					// property fieldname
+					int idx = fieldName.indexOf(':');
+					fieldName = fieldName.substring(0,
+						idx + 1)
+						+ FieldNames.FULLTEXT_PREFIX
+						+ fieldName.substring(idx + 1);
+					Object prevAnalyzer = analyzers.put(
+						fieldName, analyzer);
+					if (prevAnalyzer != null) {
+					    log
+						    .warn("Property "
+							    + propName
+								    .getName()
+							    + " has been configured for multiple analyzers. "
+							    + " Last configured analyzer is used");
+					}
+				    }
+				}
+			    } else {
+				log
+					.warn("org.apache.lucene.analysis.Analyzer is not a superclass of "
+						+ analyzerClassName
+						+ ". Ignoring this configure analyzer");
+			    }
+			} catch (ClassNotFoundException e) {
+			    log.warn("Analyzer class not found: "
+				    + analyzerClassName, e);
+			}
+		    }
+		}
+	    }
 
-      }
-      aggregateRules = (AggregateRule[])idxAggregates.toArray(new AggregateRule[idxAggregates.size()]);
-   }
+	}
+	aggregateRules = idxAggregates.toArray(new AggregateRule[idxAggregates
+		.size()]);
+    }
 
-   /**
-    * Returns the configured indexing aggregate rules or <code>null</code> if
-    * none exist.
-    *
-    * @return the configured rules or <code>null</code> if none exist.
-    */
-   public AggregateRule[] getAggregateRules()
-   {
-      return aggregateRules;
-   }
+    /**
+     * Returns the configured indexing aggregate rules or <code>null</code> if
+     * none exist.
+     * 
+     * @return the configured rules or <code>null</code> if none exist.
+     */
+    public AggregateRule[] getAggregateRules() {
+	return aggregateRules;
+    }
 
-   /**
-    * Returns <code>true</code> if the property with the given name is fulltext
-    * indexed according to this configuration.
-    *
-    * @param state        the node state.
-    * @param propertyName the name of a property.
-    * @return <code>true</code> if the property is fulltext indexed;
-    *         <code>false</code> otherwise.
-    */
-   public boolean isIndexed(NodeData state, InternalQName propertyName)
-   {
-      IndexingRule rule = getApplicableIndexingRule(state);
-      if (rule != null)
-      {
-         return rule.isIndexed(propertyName);
-      }
-      // none of the configs matches -> index property
-      return true;
-   }
+    /**
+     * Returns <code>true</code> if the property with the given name is fulltext
+     * indexed according to this configuration.
+     * 
+     * @param state
+     *            the node state.
+     * @param propertyName
+     *            the name of a property.
+     * @return <code>true</code> if the property is fulltext indexed;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isIndexed(NodeData state, InternalQName propertyName) {
+	IndexingRule rule = getApplicableIndexingRule(state);
+	if (rule != null) {
+	    return rule.isIndexed(propertyName);
+	}
+	// none of the configs matches -> index property
+	return true;
+    }
 
-   /**
-    * Returns the boost value for the given property name. If there is no
-    * configuration entry for the property name the {@link #DEFAULT_BOOST} is
-    * returned.
-    *
-    * @param state        the node state.
-    * @param propertyName the name of a property.
-    * @return the boost value for the property.
-    */
-   public float getPropertyBoost(NodeData state, InternalQName propertyName)
-   {
-      IndexingRule rule = getApplicableIndexingRule(state);
-      if (rule != null)
-      {
-         return rule.getBoost(propertyName);
-      }
-      return DEFAULT_BOOST;
-   }
+    /**
+     * Returns the boost value for the given property name. If there is no
+     * configuration entry for the property name the {@link #DEFAULT_BOOST} is
+     * returned.
+     * 
+     * @param state
+     *            the node state.
+     * @param propertyName
+     *            the name of a property.
+     * @return the boost value for the property.
+     */
+    public float getPropertyBoost(NodeData state, InternalQName propertyName) {
+	IndexingRule rule = getApplicableIndexingRule(state);
+	if (rule != null) {
+	    return rule.getBoost(propertyName);
+	}
+	return DEFAULT_BOOST;
+    }
 
-   /**
-    * Returns the boost for the node scope fulltext index field.
-    *
-    * @param state the node state.
-    * @return the boost for the node scope fulltext index field.
-    */
-   public float getNodeBoost(NodeData state)
-   {
-      IndexingRule rule = getApplicableIndexingRule(state);
-      if (rule != null)
-      {
-         return rule.getNodeBoost();
-      }
-      return DEFAULT_BOOST;
-   }
+    /**
+     * Returns the boost for the node scope fulltext index field.
+     * 
+     * @param state
+     *            the node state.
+     * @return the boost for the node scope fulltext index field.
+     */
+    public float getNodeBoost(NodeData state) {
+	IndexingRule rule = getApplicableIndexingRule(state);
+	if (rule != null) {
+	    return rule.getNodeBoost();
+	}
+	return DEFAULT_BOOST;
+    }
 
-   /**
-    * Returns <code>true</code> if the property with the given name should be
-    * included in the node scope fulltext index. If there is not configuration
-    * entry for that propery <code>false</code> is returned.
-    *
-    * @param state the node state.
-    * @param propertyName the name of a property.
-    * @return <code>true</code> if the property should be included in the node
-    *         scope fulltext index.
-    */
-   public boolean isIncludedInNodeScopeIndex(NodeData state, InternalQName propertyName)
-   {
-      IndexingRule rule = getApplicableIndexingRule(state);
-      if (rule != null)
-      {
-         return rule.isIncludedInNodeScopeIndex(propertyName);
-      }
-      // none of the config elements matched -> default is to include
-      return true;
-   }
+    /**
+     * Returns <code>true</code> if the property with the given name should be
+     * included in the node scope fulltext index. If there is not configuration
+     * entry for that propery <code>false</code> is returned.
+     * 
+     * @param state
+     *            the node state.
+     * @param propertyName
+     *            the name of a property.
+     * @return <code>true</code> if the property should be included in the node
+     *         scope fulltext index.
+     */
+    public boolean isIncludedInNodeScopeIndex(NodeData state,
+	    InternalQName propertyName) {
+	IndexingRule rule = getApplicableIndexingRule(state);
+	if (rule != null) {
+	    return rule.isIncludedInNodeScopeIndex(propertyName);
+	}
+	// none of the config elements matched -> default is to include
+	return true;
+    }
 
-   /**
-    * Returns <code>true</code> if the content of the property with the given
-    * name should show up in an excerpt. If there is no configuration entry for
-    * that property <code>true</code> is returned.
-    *
-    * @param state the node state.
-    * @param propertyName the name of a property.
-    * @return <code>true</code> if the content of the property should be
-    *         included in an excerpt; <code>false</code> otherwise.
-    */
-   public boolean useInExcerpt(NodeData state, InternalQName propertyName)
-   {
-      IndexingRule rule = getApplicableIndexingRule(state);
-      if (rule != null)
-      {
-         return rule.useInExcerpt(propertyName);
-      }
-      // none of the config elements matched -> default is to include
-      return true;
-   }
+    /**
+     * Returns <code>true</code> if the content of the property with the given
+     * name should show up in an excerpt. If there is no configuration entry for
+     * that property <code>true</code> is returned.
+     * 
+     * @param state
+     *            the node state.
+     * @param propertyName
+     *            the name of a property.
+     * @return <code>true</code> if the content of the property should be
+     *         included in an excerpt; <code>false</code> otherwise.
+     */
+    public boolean useInExcerpt(NodeData state, InternalQName propertyName) {
+	IndexingRule rule = getApplicableIndexingRule(state);
+	if (rule != null) {
+	    return rule.useInExcerpt(propertyName);
+	}
+	// none of the config elements matched -> default is to include
+	return true;
+    }
 
-   /**
-    * Returns the analyzer configured for the property with this fieldName
-    * (the string representation ,JCR-style name, of the given <code>InternalQName</code>
-    * prefixed with <code>FieldNames.FULLTEXT_PREFIX</code>)),
-    * and <code>null</code> if none is configured, or the configured analyzer
-    * cannot be found. If <code>null</code> is returned, the default Analyzer
-    * is used.
-    *
-    * @param fieldName the string representation ,JCR-style name, of the given <code>InternalQName</code>
-    * prefixed with <code>FieldNames.FULLTEXT_PREFIX</code>))
-    * @return the <code>analyzer</code> to use for indexing this property
-    */
-   public Analyzer getPropertyAnalyzer(String fieldName)
-   {
-      if (analyzers.containsKey(fieldName))
-      {
-         return (Analyzer)analyzers.get(fieldName);
-      }
-      return null;
-   }
+    /**
+     * Returns the analyzer configured for the property with this fieldName (the
+     * string representation ,JCR-style name, of the given
+     * <code>InternalQName</code> prefixed with
+     * <code>FieldNames.FULLTEXT_PREFIX</code>)), and <code>null</code> if none
+     * is configured, or the configured analyzer cannot be found. If
+     * <code>null</code> is returned, the default Analyzer is used.
+     * 
+     * @param fieldName
+     *            the string representation ,JCR-style name, of the given
+     *            <code>InternalQName</code> prefixed with
+     *            <code>FieldNames.FULLTEXT_PREFIX</code>))
+     * @return the <code>analyzer</code> to use for indexing this property
+     */
+    public Analyzer getPropertyAnalyzer(String fieldName) {
+	if (analyzers.containsKey(fieldName)) {
+	    return analyzers.get(fieldName);
+	}
+	return null;
+    }
 
-   //---------------------------------< internal >-----------------------------
+    // ---------------------------------< internal
+    // >-----------------------------
 
-   /**
-    * Returns the first indexing rule that applies to the given node
-    * <code>state</code>.
-    *
-    * @param state a node state.
-    * @return the indexing rule or <code>null</code> if none applies.
-    */
-   private IndexingRule getApplicableIndexingRule(NodeData state)
-   {
-      List rules = null;
-      List r = (List)configElements.get(state.getPrimaryTypeName());
-      if (r != null)
-      {
-         rules = new ArrayList();
-         rules.addAll(r);
-      }
+    /**
+     * Returns the first indexing rule that applies to the given node
+     * <code>state</code>.
+     * 
+     * @param state
+     *            a node state.
+     * @return the indexing rule or <code>null</code> if none applies.
+     */
+    private IndexingRule getApplicableIndexingRule(NodeData state) {
+	List<IndexingRule> rules = null;
+	List<IndexingRule> r = configElements.get(state.getPrimaryTypeName());
+	if (r != null) {
+	    rules = new ArrayList<IndexingRule>();
+	    rules.addAll(r);
+	}
 
-      Iterator it = Arrays.asList(state.getMixinTypeNames()).iterator();
-      while (it.hasNext())
-      {
-         r = (List)configElements.get(it.next());
-         if (r != null)
-         {
-            if (rules == null)
-            {
-               rules = new ArrayList();
-            }
-            rules.addAll(r);
-         }
-      }
+	InternalQName[] mixTypes = state.getMixinTypeNames();
+	for (InternalQName mixType : mixTypes) {
+	    r = configElements.get(mixType);
+	    if (r != null) {
+		if (rules == null) {
+		    rules = new ArrayList<IndexingRule>();
+		}
+		rules.addAll(r);
+	    }
+	}
 
-      if (rules != null)
-      {
-         it = rules.iterator();
-         while (it.hasNext())
-         {
-            IndexingRule ir = (IndexingRule)it.next();
-            if (ir.appliesTo(state))
-            {
-               return ir;
-            }
-         }
-      }
+	if (rules != null) {
+	    for (IndexingRule ir : rules) {
+		if (ir.appliesTo(state)) {
+		    return ir;
+		}
+	    }
+	}
 
-      // no applicable rule
-      return null;
-   }
+	// no applicable rule
+	return null;
+    }
 
-   /**
-    * Returns the namespaces declared on the <code>node</code>.
-    *
-    * @param node a DOM node.
-    * @return the namespaces
-    */
-   private Properties getNamespaces(Node node)
-   {
-      Properties namespaces = new Properties();
-      NamedNodeMap attributes = node.getAttributes();
-      for (int i = 0; i < attributes.getLength(); i++)
-      {
-         Attr attribute = (Attr)attributes.item(i);
-         if (attribute.getName().startsWith("xmlns:"))
-         {
-            namespaces.setProperty(attribute.getName().substring(6), attribute.getValue());
-         }
-      }
-      return namespaces;
-   }
+    /**
+     * Returns the namespaces declared on the <code>node</code>.
+     * 
+     * @param node
+     *            a DOM node.
+     * @return the namespaces
+     */
+    private Properties getNamespaces(Node node) {
+	Properties namespaces = new Properties();
+	NamedNodeMap attributes = node.getAttributes();
+	for (int i = 0; i < attributes.getLength(); i++) {
+	    Attr attribute = (Attr) attributes.item(i);
+	    if (attribute.getName().startsWith("xmlns:")) {
+		namespaces.setProperty(attribute.getName().substring(6),
+			attribute.getValue());
+	    }
+	}
+	return namespaces;
+    }
 
-   /**
-    * Creates property configurations defined in the <code>config</code>.
-    *
-    * @param config the fulltext indexing configuration.
-    * @param propConfigs will be filled with exact <code>InternalQName</code> to
-    *                    <code>PropertyConfig</code> mappings.
-    * @param namePatterns will be filled with <code>NamePattern</code>s.
-    * @throws IllegalNameException   if the node type name contains illegal
-    *                                characters.
-   * @throws RepositoryException 
-    */
-   private void createPropertyConfigs(Node config, Map propConfigs, List namePatterns) throws IllegalNameException,
-      RepositoryException
-   {
-      NodeList childNodes = config.getChildNodes();
-      for (int i = 0; i < childNodes.getLength(); i++)
-      {
-         Node n = childNodes.item(i);
-         if (n.getNodeName().equals("property"))
-         {
-            NamedNodeMap attributes = n.getAttributes();
-            // get boost value
-            float boost = 1.0f;
-            Node boostAttr = attributes.getNamedItem("boost");
-            if (boostAttr != null)
-            {
-               try
-               {
-                  boost = Float.parseFloat(boostAttr.getNodeValue());
-               }
-               catch (NumberFormatException e)
-               {
-                  // use default
-               }
-            }
+    /**
+     * Creates property configurations defined in the <code>config</code>.
+     * 
+     * @param config
+     *            the fulltext indexing configuration.
+     * @param propConfigs
+     *            will be filled with exact <code>InternalQName</code> to
+     *            <code>PropertyConfig</code> mappings.
+     * @param namePatterns
+     *            will be filled with <code>NamePattern</code>s.
+     * @throws IllegalNameException
+     *             if the node type name contains illegal characters.
+     * @throws RepositoryException
+     */
+    private void createPropertyConfigs(Node config,
+	    Map<InternalQName, PropertyConfig> propConfigs,
+	    List<NamePattern> namePatterns) throws IllegalNameException,
+	    RepositoryException {
+	NodeList childNodes = config.getChildNodes();
+	for (int i = 0; i < childNodes.getLength(); i++) {
+	    Node n = childNodes.item(i);
+	    if (n.getNodeName().equals("property")) {
+		NamedNodeMap attributes = n.getAttributes();
+		// get boost value
+		float boost = 1.0f;
+		Node boostAttr = attributes.getNamedItem("boost");
+		if (boostAttr != null) {
+		    try {
+			boost = Float.parseFloat(boostAttr.getNodeValue());
+		    } catch (NumberFormatException e) {
+			// use default
+		    }
+		}
 
-            // get nodeScopeIndex flag
-            boolean nodeScopeIndex = true;
-            Node nsIndex = attributes.getNamedItem("nodeScopeIndex");
-            if (nsIndex != null)
-            {
-               nodeScopeIndex = Boolean.valueOf(nsIndex.getNodeValue()).booleanValue();
-            }
+		// get nodeScopeIndex flag
+		boolean nodeScopeIndex = true;
+		Node nsIndex = attributes.getNamedItem("nodeScopeIndex");
+		if (nsIndex != null) {
+		    nodeScopeIndex = Boolean.valueOf(nsIndex.getNodeValue())
+			    .booleanValue();
+		}
 
-            // get isRegexp flag
-            boolean isRegexp = false;
-            Node regexp = attributes.getNamedItem("isRegexp");
-            if (regexp != null)
-            {
-               isRegexp = Boolean.valueOf(regexp.getNodeValue()).booleanValue();
-            }
+		// get isRegexp flag
+		boolean isRegexp = false;
+		Node regexp = attributes.getNamedItem("isRegexp");
+		if (regexp != null) {
+		    isRegexp = Boolean.valueOf(regexp.getNodeValue())
+			    .booleanValue();
+		}
 
-            // get useInExcerpt flag
-            boolean useInExcerpt = true;
-            Node excerpt = attributes.getNamedItem("useInExcerpt");
-            if (excerpt != null)
-            {
-               useInExcerpt = Boolean.valueOf(excerpt.getNodeValue()).booleanValue();
-            }
+		// get useInExcerpt flag
+		boolean useInExcerpt = true;
+		Node excerpt = attributes.getNamedItem("useInExcerpt");
+		if (excerpt != null) {
+		    useInExcerpt = Boolean.valueOf(excerpt.getNodeValue())
+			    .booleanValue();
+		}
 
-            PropertyConfig pc = new PropertyConfig(boost, nodeScopeIndex, useInExcerpt);
+		PropertyConfig pc = new PropertyConfig(boost, nodeScopeIndex,
+			useInExcerpt);
 
-            if (isRegexp)
-            {
-               namePatterns.add(new NamePattern(getTextContent(n), pc, resolver));
-            }
-            else
-            {
-               InternalQName propName = resolver.parseJCRName(getTextContent(n)).getInternalName();
-               propConfigs.put(propName, pc);
-            }
-         }
-      }
-   }
+		if (isRegexp) {
+		    namePatterns.add(new NamePattern(getTextContent(n), pc,
+			    resolver));
+		} else {
+		    InternalQName propName = resolver.parseJCRName(
+			    getTextContent(n)).getInternalName();
+		    propConfigs.put(propName, pc);
+		}
+	    }
+	}
+    }
 
-   /**
-    * Gets the condition expression from the configuration.
-    *
-    * @param config the config node.
-    * @return the condition expression or <code>null</code> if there is no
-    *         condition set on the <code>config</code>.
-    * @throws MalformedPathException if the condition string is malformed.
-    * @throws IllegalNameException   if a name contains illegal characters.
-   * @throws RepositoryException 
-    */
-   private PathExpression getCondition(Node config) throws IllegalNameException, RepositoryException
-   {
-      Node conditionAttr = config.getAttributes().getNamedItem("condition");
-      if (conditionAttr == null)
-      {
-         return null;
-      }
-      String conditionString = conditionAttr.getNodeValue();
-      int idx;
-      int axis;
-      InternalQName elementTest = null;
-      InternalQName nameTest = null;
-      InternalQName propertyName;
-      String propertyValue;
+    /**
+     * Gets the condition expression from the configuration.
+     * 
+     * @param config
+     *            the config node.
+     * @return the condition expression or <code>null</code> if there is no
+     *         condition set on the <code>config</code>.
+     * @throws MalformedPathException
+     *             if the condition string is malformed.
+     * @throws IllegalNameException
+     *             if a name contains illegal characters.
+     * @throws RepositoryException
+     */
+    private PathExpression getCondition(Node config)
+	    throws IllegalNameException, RepositoryException {
+	Node conditionAttr = config.getAttributes().getNamedItem("condition");
+	if (conditionAttr == null) {
+	    return null;
+	}
+	String conditionString = conditionAttr.getNodeValue();
+	int idx;
+	int axis;
+	InternalQName elementTest = null;
+	InternalQName nameTest = null;
+	InternalQName propertyName;
+	String propertyValue;
 
-      // parse axis
-      if (conditionString.startsWith("ancestor::"))
-      {
-         axis = PathExpression.ANCESTOR;
-         idx = "ancestor::".length();
-      }
-      else if (conditionString.startsWith("parent::"))
-      {
-         axis = PathExpression.PARENT;
-         idx = "parent::".length();
-      }
-      else if (conditionString.startsWith("@"))
-      {
-         axis = PathExpression.SELF;
-         idx = "@".length();
-      }
-      else
-      {
-         axis = PathExpression.CHILD;
-         idx = 0;
-      }
+	// parse axis
+	if (conditionString.startsWith("ancestor::")) {
+	    axis = PathExpression.ANCESTOR;
+	    idx = "ancestor::".length();
+	} else if (conditionString.startsWith("parent::")) {
+	    axis = PathExpression.PARENT;
+	    idx = "parent::".length();
+	} else if (conditionString.startsWith("@")) {
+	    axis = PathExpression.SELF;
+	    idx = "@".length();
+	} else {
+	    axis = PathExpression.CHILD;
+	    idx = 0;
+	}
 
-      try
-      {
-         if (conditionString.startsWith("element(", idx))
-         {
-            int colon = conditionString.indexOf(',', idx + "element(".length());
-            String name = conditionString.substring(idx + "element(".length(), colon).trim();
-            if (!name.equals("*"))
-            {
-               nameTest = resolver.parseJCRName(ISO9075.decode(name)).getInternalName();
-            }
-            idx = conditionString.indexOf(")/@", colon);
-            String type = conditionString.substring(colon + 1, idx).trim();
-            elementTest = resolver.parseJCRName(ISO9075.decode(type)).getInternalName();
-            idx += ")/@".length();
-         }
-         else
-         {
-            if (axis == PathExpression.ANCESTOR || axis == PathExpression.CHILD || axis == PathExpression.PARENT)
-            {
-               // simple name test
-               String name = conditionString.substring(idx, conditionString.indexOf('/', idx));
-               if (!name.equals("*"))
-               {
-                  nameTest = resolver.parseJCRName(ISO9075.decode(name)).getInternalName();
-               }
-               idx += name.length() + "/@".length();
-            }
-         }
+	try {
+	    if (conditionString.startsWith("element(", idx)) {
+		int colon = conditionString.indexOf(',', idx
+			+ "element(".length());
+		String name = conditionString.substring(
+			idx + "element(".length(), colon).trim();
+		if (!name.equals("*")) {
+		    nameTest = resolver.parseJCRName(ISO9075.decode(name))
+			    .getInternalName();
+		}
+		idx = conditionString.indexOf(")/@", colon);
+		String type = conditionString.substring(colon + 1, idx).trim();
+		elementTest = resolver.parseJCRName(ISO9075.decode(type))
+			.getInternalName();
+		idx += ")/@".length();
+	    } else {
+		if (axis == PathExpression.ANCESTOR
+			|| axis == PathExpression.CHILD
+			|| axis == PathExpression.PARENT) {
+		    // simple name test
+		    String name = conditionString.substring(idx,
+			    conditionString.indexOf('/', idx));
+		    if (!name.equals("*")) {
+			nameTest = resolver.parseJCRName(ISO9075.decode(name))
+				.getInternalName();
+		    }
+		    idx += name.length() + "/@".length();
+		}
+	    }
 
-         // parse property name
-         int eq = conditionString.indexOf('=', idx);
-         String name = conditionString.substring(idx, eq).trim();
-         propertyName = resolver.parseJCRName(ISO9075.decode(name)).getInternalName();
+	    // parse property name
+	    int eq = conditionString.indexOf('=', idx);
+	    String name = conditionString.substring(idx, eq).trim();
+	    propertyName = resolver.parseJCRName(ISO9075.decode(name))
+		    .getInternalName();
 
-         // parse string value
-         int quote = conditionString.indexOf('\'', eq) + 1;
-         propertyValue = conditionString.substring(quote, conditionString.indexOf('\'', quote));
-      }
-      catch (IndexOutOfBoundsException e)
-      {
-         throw new RepositoryException(conditionString);
-      }
+	    // parse string value
+	    int quote = conditionString.indexOf('\'', eq) + 1;
+	    propertyValue = conditionString.substring(quote, conditionString
+		    .indexOf('\'', quote));
+	} catch (IndexOutOfBoundsException e) {
+	    throw new RepositoryException(conditionString);
+	}
 
-      return new PathExpression(axis, elementTest, nameTest, propertyName, propertyValue);
-   }
+	return new PathExpression(axis, elementTest, nameTest, propertyName,
+		propertyValue);
+    }
 
-   /**
-    * @param node a node.
-    * @return the text content of the <code>node</code>.
-    */
-   private static String getTextContent(Node node)
-   {
-      StringBuffer content = new StringBuffer();
-      NodeList nodes = node.getChildNodes();
-      for (int i = 0; i < nodes.getLength(); i++)
-      {
-         Node n = nodes.item(i);
-         if (n.getNodeType() == Node.TEXT_NODE)
-         {
-            content.append(((CharacterData)n).getData());
-         }
-      }
-      return content.toString();
-   }
+    /**
+     * @param node
+     *            a node.
+     * @return the text content of the <code>node</code>.
+     */
+    private static String getTextContent(Node node) {
+	StringBuffer content = new StringBuffer();
+	NodeList nodes = node.getChildNodes();
+	for (int i = 0; i < nodes.getLength(); i++) {
+	    Node n = nodes.item(i);
+	    if (n.getNodeType() == Node.TEXT_NODE) {
+		content.append(((CharacterData) n).getData());
+	    }
+	}
+	return content.toString();
+    }
 
-   /**
-    * A property name pattern.
-    */
-   private static final class NamePattern
-   {
+    /**
+     * A property name pattern.
+     */
+    private static final class NamePattern {
 
-      /**
-       * The pattern to match.
-       */
-      private final Pattern pattern;
+	/**
+	 * The pattern to match.
+	 */
+	private final Pattern pattern;
 
-      /**
-       * The associated configuration.
-       */
-      private final PropertyConfig config;
+	/**
+	 * The associated configuration.
+	 */
+	private final PropertyConfig config;
 
-      /**
-       * Creates a new name pattern.
-       *
-       * @param pattern the pattern as read from the configuration file.
-       * @param config the associated configuration.
-       * @param resolver a namespace resolver for parsing name from the
-       *                 configuration.
-       * @throws IllegalNameException if the prefix of the name pattern is
-       *                              illegal.
-      * @throws RepositoryException 
-       */
-      private NamePattern(String pattern, PropertyConfig config, LocationFactory resolver) throws IllegalNameException,
-         RepositoryException
-      {
-         String uri = Constants.NS_DEFAULT_URI;
-         String localPattern = pattern;
-         int idx = pattern.indexOf(':');
-         if (idx != -1)
-         {
-            // use a dummy local name to get namespace uri
-            uri = resolver.parseJCRName(pattern.substring(0, idx) + ":a").getNamespace();
-            localPattern = pattern.substring(idx + 1);
-         }
-         this.pattern = Pattern.name(uri, localPattern);
-         this.config = config;
-      }
+	/**
+	 * Creates a new name pattern.
+	 * 
+	 * @param pattern
+	 *            the pattern as read from the configuration file.
+	 * @param config
+	 *            the associated configuration.
+	 * @param resolver
+	 *            a namespace resolver for parsing name from the
+	 *            configuration.
+	 * @throws IllegalNameException
+	 *             if the prefix of the name pattern is illegal.
+	 * @throws RepositoryException
+	 */
+	private NamePattern(String pattern, PropertyConfig config,
+		LocationFactory resolver) throws IllegalNameException,
+		RepositoryException {
+	    String uri = Constants.NS_DEFAULT_URI;
+	    String localPattern = pattern;
+	    int idx = pattern.indexOf(':');
+	    if (idx != -1) {
+		// use a dummy local name to get namespace uri
+		uri = resolver.parseJCRName(pattern.substring(0, idx) + ":a")
+			.getNamespace();
+		localPattern = pattern.substring(idx + 1);
+	    }
+	    this.pattern = Pattern.name(uri, localPattern);
+	    this.config = config;
+	}
 
-      /**
-       * @param path the path to match.
-       * @return <code>true</code> if <code>path</code> matches this name
-       *         pattern; <code>false</code> otherwise.
-       */
-      boolean matches(QPath path)
-      {
-         return pattern.match(path).isFullMatch();
-      }
+	/**
+	 * @param path
+	 *            the path to match.
+	 * @return <code>true</code> if <code>path</code> matches this name
+	 *         pattern; <code>false</code> otherwise.
+	 */
+	boolean matches(QPath path) {
+	    return pattern.match(path).isFullMatch();
+	}
 
-      /**
-       * @return the property configuration for this name pattern.
-       */
-      PropertyConfig getConfig()
-      {
-         return config;
-      }
-   }
+	/**
+	 * @return the property configuration for this name pattern.
+	 */
+	PropertyConfig getConfig() {
+	    return config;
+	}
+    }
 
-   private class IndexingRule
-   {
+    private class IndexingRule {
 
-      /**
-       * The node type of this fulltext indexing rule.
-       */
-      private final InternalQName nodeTypeName;
+	/**
+	 * The node type of this fulltext indexing rule.
+	 */
+	private final InternalQName nodeTypeName;
 
-      /**
-       * Map of {@link PropertyConfig}. Key=InternalQName of property.
-       */
-      private final Map propConfigs;
+	/**
+	 * Map of {@link PropertyConfig}. Key=InternalQName of property.
+	 */
+	private final Map<InternalQName, PropertyConfig> propConfigs;
 
-      /**
-       * List of {@link NamePattern}s.
-       */
-      private final List namePatterns;
+	/**
+	 * List of {@link NamePattern}s.
+	 */
+	private final List<NamePattern> namePatterns;
 
-      /**
-       * An expression based on a relative path.
-       */
-      private final PathExpression condition;
+	/**
+	 * An expression based on a relative path.
+	 */
+	private final PathExpression condition;
 
-      /**
-       * The boost value for this config element.
-       */
-      private final float boost;
+	/**
+	 * The boost value for this config element.
+	 */
+	private final float boost;
 
-      /**
-       * Creates a new indexing rule base on an existing one, but for a
-       * different node type name.
-       *
-       * @param original the existing rule.
-       * @param nodeTypeName the node type name for the rule.
-       */
-      IndexingRule(IndexingRule original, InternalQName nodeTypeName)
-      {
-         this.nodeTypeName = nodeTypeName;
-         this.propConfigs = original.propConfigs;
-         this.namePatterns = original.namePatterns;
-         this.condition = original.condition;
-         this.boost = original.boost;
-      }
+	/**
+	 * Creates a new indexing rule base on an existing one, but for a
+	 * different node type name.
+	 * 
+	 * @param original
+	 *            the existing rule.
+	 * @param nodeTypeName
+	 *            the node type name for the rule.
+	 */
+	IndexingRule(IndexingRule original, InternalQName nodeTypeName) {
+	    this.nodeTypeName = nodeTypeName;
+	    this.propConfigs = original.propConfigs;
+	    this.namePatterns = original.namePatterns;
+	    this.condition = original.condition;
+	    this.boost = original.boost;
+	}
 
-      /**
-       *
-       * @param config the configuration for this rule.
-       * @throws MalformedPathException if the condition expression is malformed.
-       * @throws IllegalNameException   if a name contains illegal characters.
-      * @throws RepositoryException 
-       */
-      IndexingRule(Node config) throws IllegalNameException, RepositoryException
-      {
-         this.nodeTypeName = getNodeTypeName(config);
-         this.condition = getCondition(config);
-         this.boost = getNodeBoost(config);
-         this.propConfigs = new HashMap();
-         this.namePatterns = new ArrayList();
-         createPropertyConfigs(config, propConfigs, namePatterns);
-      }
+	/**
+	 * 
+	 * @param config
+	 *            the configuration for this rule.
+	 * @throws MalformedPathException
+	 *             if the condition expression is malformed.
+	 * @throws IllegalNameException
+	 *             if a name contains illegal characters.
+	 * @throws RepositoryException
+	 */
+	IndexingRule(Node config) throws IllegalNameException,
+		RepositoryException {
+	    this.nodeTypeName = getNodeTypeName(config);
+	    this.condition = getCondition(config);
+	    this.boost = getNodeBoost(config);
+	    this.propConfigs = new HashMap<InternalQName, PropertyConfig>();
+	    this.namePatterns = new ArrayList<NamePattern>();
+	    createPropertyConfigs(config, propConfigs, namePatterns);
+	}
 
-      /**
-       * Returns the name of the node type where this rule applies to.
-       *
-       * @return name of the node type.
-       */
-      public InternalQName getNodeTypeName()
-      {
-         return nodeTypeName;
-      }
+	/**
+	 * Returns the name of the node type where this rule applies to.
+	 * 
+	 * @return name of the node type.
+	 */
+	public InternalQName getNodeTypeName() {
+	    return nodeTypeName;
+	}
 
-      /**
-       * @return the value for the node boost.
-       */
-      public float getNodeBoost()
-      {
-         return boost;
-      }
+	/**
+	 * @return the value for the node boost.
+	 */
+	public float getNodeBoost() {
+	    return boost;
+	}
 
-      /**
-       * Returns <code>true</code> if the property with the given name is
-       * indexed according to this rule.
-       *
-       * @param propertyName the name of a property.
-       * @return <code>true</code> if the property is indexed;
-       *         <code>false</code> otherwise.
-       */
-      public boolean isIndexed(InternalQName propertyName)
-      {
-         return getConfig(propertyName) != null;
-      }
+	/**
+	 * Returns <code>true</code> if the property with the given name is
+	 * indexed according to this rule.
+	 * 
+	 * @param propertyName
+	 *            the name of a property.
+	 * @return <code>true</code> if the property is indexed;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean isIndexed(InternalQName propertyName) {
+	    return getConfig(propertyName) != null;
+	}
 
-      /**
-       * Returns the boost value for the given property name. If there is no
-       * configuration entry for the property name the default boost value is
-       * returned.
-       *
-       * @param propertyName the name of a property.
-       * @return the boost value for the property.
-       */
-      public float getBoost(InternalQName propertyName)
-      {
-         PropertyConfig config = getConfig(propertyName);
-         if (config != null)
-         {
-            return config.boost;
-         }
-         else
-         {
-            return DEFAULT_BOOST;
-         }
-      }
+	/**
+	 * Returns the boost value for the given property name. If there is no
+	 * configuration entry for the property name the default boost value is
+	 * returned.
+	 * 
+	 * @param propertyName
+	 *            the name of a property.
+	 * @return the boost value for the property.
+	 */
+	public float getBoost(InternalQName propertyName) {
+	    PropertyConfig config = getConfig(propertyName);
+	    if (config != null) {
+		return config.boost;
+	    } else {
+		return DEFAULT_BOOST;
+	    }
+	}
 
-      /**
-       * Returns <code>true</code> if the property with the given name should
-       * be included in the node scope fulltext index. If there is no
-       * configuration entry for that propery <code>false</code> is returned.
-       *
-       * @param propertyName the name of a property.
-       * @return <code>true</code> if the property should be included in the
-       *         node scope fulltext index.
-       */
-      public boolean isIncludedInNodeScopeIndex(InternalQName propertyName)
-      {
-         PropertyConfig config = getConfig(propertyName);
-         if (config != null)
-         {
-            return config.nodeScopeIndex;
-         }
-         else
-         {
-            return false;
-         }
-      }
+	/**
+	 * Returns <code>true</code> if the property with the given name should
+	 * be included in the node scope fulltext index. If there is no
+	 * configuration entry for that propery <code>false</code> is returned.
+	 * 
+	 * @param propertyName
+	 *            the name of a property.
+	 * @return <code>true</code> if the property should be included in the
+	 *         node scope fulltext index.
+	 */
+	public boolean isIncludedInNodeScopeIndex(InternalQName propertyName) {
+	    PropertyConfig config = getConfig(propertyName);
+	    if (config != null) {
+		return config.nodeScopeIndex;
+	    } else {
+		return false;
+	    }
+	}
 
-      /**
-       * Returns <code>true</code> if the content of the property with the
-       * given name should show up in an excerpt. If there is no configuration
-       * entry for that property <code>true</code> is returned.
-       *
-       * @param propertyName the name of a property.
-       * @return <code>true</code> if the content of the property should be
-       *         included in an excerpt; <code>false</code> otherwise.
-       */
-      public boolean useInExcerpt(InternalQName propertyName)
-      {
-         PropertyConfig config = getConfig(propertyName);
-         if (config != null)
-         {
-            return config.useInExcerpt;
-         }
-         else
-         {
-            return true;
-         }
-      }
+	/**
+	 * Returns <code>true</code> if the content of the property with the
+	 * given name should show up in an excerpt. If there is no configuration
+	 * entry for that property <code>true</code> is returned.
+	 * 
+	 * @param propertyName
+	 *            the name of a property.
+	 * @return <code>true</code> if the content of the property should be
+	 *         included in an excerpt; <code>false</code> otherwise.
+	 */
+	public boolean useInExcerpt(InternalQName propertyName) {
+	    PropertyConfig config = getConfig(propertyName);
+	    if (config != null) {
+		return config.useInExcerpt;
+	    } else {
+		return true;
+	    }
+	}
 
-      /**
-       * Returns <code>true</code> if this rule applies to the given node
-       * <code>state</code>.
-       *
-       * @param state the state to check.
-       * @return <code>true</code> the rule applies to the given node;
-       *         <code>false</code> otherwise.
-       */
-      public boolean appliesTo(NodeData state)
-      {
-         if (!nodeTypeName.equals(state.getPrimaryTypeName()))
-         {
-            return false;
-         }
-         if (condition == null)
-         {
-            return true;
-         }
-         else
-         {
-            return condition.evaluate(state);
-         }
-      }
+	/**
+	 * Returns <code>true</code> if this rule applies to the given node
+	 * <code>state</code>.
+	 * 
+	 * @param state
+	 *            the state to check.
+	 * @return <code>true</code> the rule applies to the given node;
+	 *         <code>false</code> otherwise.
+	 */
+	public boolean appliesTo(NodeData state) {
+	    if (!nodeTypeName.equals(state.getPrimaryTypeName())) {
+		return false;
+	    }
+	    if (condition == null) {
+		return true;
+	    } else {
+		return condition.evaluate(state);
+	    }
+	}
 
-      //-------------------------< internal >---------------------------------
+	// -------------------------< internal
+	// >---------------------------------
 
-      /**
-       * @param propertyName name of a property.
-       * @return the property configuration or <code>null</code> if this
-       *         indexing rule does not contain a configuration for the given
-       *         property.
-       */
-      private PropertyConfig getConfig(InternalQName propertyName)
-      {
-         PropertyConfig config = (PropertyConfig)propConfigs.get(propertyName);
-         if (config != null)
-         {
-            return config;
-         }
-         else if (namePatterns.size() > 0)
-         {
-            QPath path = new QPath(new QPathEntry[]{new QPathEntry(propertyName, 1)});
-            // check patterns
-            for (Iterator it = namePatterns.iterator(); it.hasNext();)
-            {
-               NamePattern np = (NamePattern)it.next();
-               if (np.matches(path))
-               {
-                  return np.getConfig();
-               }
-            }
-         }
-         return null;
-      }
+	/**
+	 * @param propertyName
+	 *            name of a property.
+	 * @return the property configuration or <code>null</code> if this
+	 *         indexing rule does not contain a configuration for the given
+	 *         property.
+	 */
+	private PropertyConfig getConfig(InternalQName propertyName) {
+	    PropertyConfig config = propConfigs.get(propertyName);
+	    if (config != null) {
+		return config;
+	    } else if (namePatterns.size() > 0) {
+		QPath path = new QPath(new QPathEntry[] { new QPathEntry(
+			propertyName, 1) });
+		// check patterns
+		for (Iterator<NamePattern> it = namePatterns.iterator(); it
+			.hasNext();) {
+		    NamePattern np = it.next();
+		    if (np.matches(path)) {
+			return np.getConfig();
+		    }
+		}
+	    }
+	    return null;
+	}
 
-      /**
-       * Reads the node type of the root node of the indexing rule.
-       *
-       * @param config the configuration.
-       * @return the name of the node type.
-       * @throws IllegalNameException   if the node type name contains illegal
-       *                                characters.
-       * @throws RepositoryException 
-       */
-      private InternalQName getNodeTypeName(Node config) throws IllegalNameException, RepositoryException
-      {
-         String ntString = config.getAttributes().getNamedItem("nodeType").getNodeValue();
-         return resolver.parseJCRName(ntString).getInternalName();
-      }
+	/**
+	 * Reads the node type of the root node of the indexing rule.
+	 * 
+	 * @param config
+	 *            the configuration.
+	 * @return the name of the node type.
+	 * @throws IllegalNameException
+	 *             if the node type name contains illegal characters.
+	 * @throws RepositoryException
+	 */
+	private InternalQName getNodeTypeName(Node config)
+		throws IllegalNameException, RepositoryException {
+	    String ntString = config.getAttributes().getNamedItem("nodeType")
+		    .getNodeValue();
+	    return resolver.parseJCRName(ntString).getInternalName();
+	}
 
-      /**
-       * Returns the node boost from the <code>config</code>.
-       *
-       * @param config the configuration.
-       * @return the configured node boost or the default boost if none is
-       *         configured.
-       */
-      private float getNodeBoost(Node config)
-      {
-         Node boost = config.getAttributes().getNamedItem("boost");
-         if (boost != null)
-         {
-            try
-            {
-               return Float.parseFloat(boost.getNodeValue());
-            }
-            catch (NumberFormatException e)
-            {
-               // return default boost
-            }
-         }
-         return DEFAULT_BOOST;
-      }
-   }
+	/**
+	 * Returns the node boost from the <code>config</code>.
+	 * 
+	 * @param config
+	 *            the configuration.
+	 * @return the configured node boost or the default boost if none is
+	 *         configured.
+	 */
+	private float getNodeBoost(Node config) {
+	    Node boost = config.getAttributes().getNamedItem("boost");
+	    if (boost != null) {
+		try {
+		    return Float.parseFloat(boost.getNodeValue());
+		} catch (NumberFormatException e) {
+		    // return default boost
+		}
+	    }
+	    return DEFAULT_BOOST;
+	}
+    }
 
-   /**
-    * Simple class that holds boost and nodeScopeIndex flag.
-    */
-   private class PropertyConfig
-   {
+    /**
+     * Simple class that holds boost and nodeScopeIndex flag.
+     */
+    private class PropertyConfig {
 
-      /**
-       * The boost value for a property.
-       */
-      final float boost;
+	/**
+	 * The boost value for a property.
+	 */
+	final float boost;
 
-      /**
-       * Flag that indicates whether a property is included in the node
-       * scope fulltext index of its parent.
-       */
-      final boolean nodeScopeIndex;
+	/**
+	 * Flag that indicates whether a property is included in the node scope
+	 * fulltext index of its parent.
+	 */
+	final boolean nodeScopeIndex;
 
-      /**
-       * Flag that indicates whether the content of a property should be used
-       * to create an excerpt.
-       */
-      final boolean useInExcerpt;
+	/**
+	 * Flag that indicates whether the content of a property should be used
+	 * to create an excerpt.
+	 */
+	final boolean useInExcerpt;
 
-      PropertyConfig(float boost, boolean nodeScopeIndex, boolean useInExcerpt)
-      {
-         this.boost = boost;
-         this.nodeScopeIndex = nodeScopeIndex;
-         this.useInExcerpt = useInExcerpt;
-      }
-   }
+	PropertyConfig(float boost, boolean nodeScopeIndex, boolean useInExcerpt) {
+	    this.boost = boost;
+	    this.nodeScopeIndex = nodeScopeIndex;
+	    this.useInExcerpt = useInExcerpt;
+	}
+    }
 
-   private class PathExpression
-   {
+    private class PathExpression {
 
-      static final int SELF = 0;
+	static final int SELF = 0;
 
-      static final int CHILD = 1;
+	static final int CHILD = 1;
 
-      static final int ANCESTOR = 2;
+	static final int ANCESTOR = 2;
 
-      static final int PARENT = 3;
+	static final int PARENT = 3;
 
-      private final int axis;
+	private final int axis;
 
-      private final InternalQName elementTest;
+	private final InternalQName elementTest;
 
-      private final InternalQName nameTest;
+	private final InternalQName nameTest;
 
-      private final InternalQName propertyName;
+	private final InternalQName propertyName;
 
-      private final String propertyValue;
+	private final String propertyValue;
 
-      PathExpression(int axis, InternalQName elementTest, InternalQName nameTest, InternalQName propertyName,
-         String propertyValue)
-      {
-         this.axis = axis;
-         this.elementTest = elementTest;
-         this.nameTest = nameTest;
-         this.propertyName = propertyName;
-         this.propertyValue = propertyValue;
-      }
+	PathExpression(int axis, InternalQName elementTest,
+		InternalQName nameTest, InternalQName propertyName,
+		String propertyValue) {
+	    this.axis = axis;
+	    this.elementTest = elementTest;
+	    this.nameTest = nameTest;
+	    this.propertyName = propertyName;
+	    this.propertyValue = propertyValue;
+	}
 
-      /**
-       * Evaluates this expression and returns <code>true</code> if the
-       * condition matches using <code>state</code> as the context node
-       * state.
-       *
-       * @param context the context from where the expression should be
-       *                evaluated.
-       * @return expression result.
-       */
-      boolean evaluate(final NodeData context)
-      {
-         // get iterator along specified axis
-         Iterator nodeStates;
-         if (axis == SELF)
-         {
-            nodeStates = Collections.singletonList(context).iterator();
-         }
-         else if (axis == CHILD)
-         {
-            List<NodeData> childs;
-            try
-            {
-               childs = ism.getChildNodesData(context);
-               nodeStates = childs.iterator();
-            }
-            catch (RepositoryException e)
-            {
-               nodeStates = Collections.<NodeData> emptyList().iterator();
-            }
-         }
-         else if (axis == ANCESTOR)
-         {
-            try
-            {
-               nodeStates = new Iterator()
-               {
+	/**
+	 * Evaluates this expression and returns <code>true</code> if the
+	 * condition matches using <code>state</code> as the context node state.
+	 * 
+	 * @param context
+	 *            the context from where the expression should be evaluated.
+	 * @return expression result.
+	 */
+	boolean evaluate(final NodeData context) {
+	    // get iterator along specified axis
+	    Iterator nodeStates;
+	    if (axis == SELF) {
+		nodeStates = Collections.singletonList(context).iterator();
+	    } else if (axis == CHILD) {
+		List<NodeData> childs;
+		try {
+		    childs = ism.getChildNodesData(context);
+		    nodeStates = childs.iterator();
+		} catch (RepositoryException e) {
+		    nodeStates = Collections.<NodeData> emptyList().iterator();
+		}
+	    } else if (axis == ANCESTOR) {
+		try {
+		    nodeStates = new Iterator() {
 
-                  private NodeData next = (NodeData)ism.getItemData(context.getParentIdentifier());
+			private NodeData next = (NodeData) ism
+				.getItemData(context.getParentIdentifier());
 
-                  public void remove()
-                  {
-                     throw new UnsupportedOperationException();
-                  }
+			public void remove() {
+			    throw new UnsupportedOperationException();
+			}
 
-                  public boolean hasNext()
-                  {
-                     return next != null;
-                  }
+			public boolean hasNext() {
+			    return next != null;
+			}
 
-                  public Object next()
-                  {
-                     NodeData tmp = next;
-                     try
-                     {
-                        if (next.getParentIdentifier() != null)
-                        {
-                           next = (NodeData)ism.getItemData(next.getParentIdentifier());
-                        }
-                        else
-                        {
-                           next = null;
-                        }
-                     }
-                     catch (RepositoryException e)
-                     {
-                        next = null;
-                     }
-                     return tmp;
-                  }
-               };
-            }
-            catch (RepositoryException e)
-            {
-               nodeStates = Collections.EMPTY_LIST.iterator();
-            }
-         }
-         else if (axis == PARENT)
-         {
-            try
-            {
-               if (context.getParentIdentifier() != null)
-               {
-                  NodeData state = (NodeData)ism.getItemData(context.getParentIdentifier());
-                  nodeStates = Collections.singletonList(state).iterator();
-               }
-               else
-               {
-                  nodeStates = Collections.EMPTY_LIST.iterator();
-               }
-            }
-            catch (RepositoryException e)
-            {
-               nodeStates = Collections.EMPTY_LIST.iterator();
-            }
-         }
-         else
-         {
-            // unsupported axis
-            nodeStates = Collections.EMPTY_LIST.iterator();
-         }
+			public Object next() {
+			    NodeData tmp = next;
+			    try {
+				if (next.getParentIdentifier() != null) {
+				    next = (NodeData) ism.getItemData(next
+					    .getParentIdentifier());
+				} else {
+				    next = null;
+				}
+			    } catch (RepositoryException e) {
+				next = null;
+			    }
+			    return tmp;
+			}
+		    };
+		} catch (RepositoryException e) {
+		    nodeStates = Collections.EMPTY_LIST.iterator();
+		}
+	    } else if (axis == PARENT) {
+		try {
+		    if (context.getParentIdentifier() != null) {
+			NodeData state = (NodeData) ism.getItemData(context
+				.getParentIdentifier());
+			nodeStates = Collections.singletonList(state)
+				.iterator();
+		    } else {
+			nodeStates = Collections.EMPTY_LIST.iterator();
+		    }
+		} catch (RepositoryException e) {
+		    nodeStates = Collections.EMPTY_LIST.iterator();
+		}
+	    } else {
+		// unsupported axis
+		nodeStates = Collections.EMPTY_LIST.iterator();
+	    }
 
-         // check node type, name and property value for each
-         while (nodeStates.hasNext())
-         {
-            try
-            {
-               NodeData current = (NodeData)nodeStates.next();
-               if ((elementTest != null) && !current.getPrimaryTypeName().equals(elementTest))
-               {
-                  continue;
-               }
-               if ((nameTest != null) && !current.getQPath().getName().equals(nameTest))
-               {
-                  continue;
-               }
+	    // check node type, name and property value for each
+	    while (nodeStates.hasNext()) {
+		try {
+		    NodeData current = (NodeData) nodeStates.next();
+		    if ((elementTest != null)
+			    && !current.getPrimaryTypeName()
+				    .equals(elementTest)) {
+			continue;
+		    }
+		    if ((nameTest != null)
+			    && !current.getQPath().getName().equals(nameTest)) {
+			continue;
+		    }
 
-               List<PropertyData> childProps = ism.getChildPropertiesData(current);
+		    List<PropertyData> childProps = ism
+			    .getChildPropertiesData(current);
 
-               PropertyData propState = null;
-               for (PropertyData propertyData : childProps)
-               {
-                  if (propertyData.getQPath().getName().equals(propertyName))
-                  {
-                     propState = propertyData;
-                     break;
-                  }
+		    PropertyData propState = null;
+		    for (PropertyData propertyData : childProps) {
+			if (propertyData.getQPath().getName().equals(
+				propertyName)) {
+			    propState = propertyData;
+			    break;
+			}
 
-               }
-               if (propState == null)
-               {
-                  continue;
-               }
+		    }
+		    if (propState == null) {
+			continue;
+		    }
 
-               List<ValueData> values = propState.getValues();
+		    List<ValueData> values = propState.getValues();
 
-               // if (values.get(i).toString().equals(propertyValue)) {
-               // return true;
-               // }
+		    // if (values.get(i).toString().equals(propertyValue)) {
+		    // return true;
+		    // }
 
-               if (propState.getType() == PropertyType.BINARY)
-               {
-                  // skip binary values
-                  continue;
-               }
+		    if (propState.getType() == PropertyType.BINARY) {
+			// skip binary values
+			continue;
+		    }
 
-               try
-               {
-                  for (int i = 0; i < values.size(); i++)
-                  {
-                     byte[] bytes = values.get(i).getAsByteArray();
-                     String val = new String(bytes, Constants.DEFAULT_ENCODING);
-                     if (val.equals(propertyValue))
-                     {
-                        return true;
-                     }
-                  }
-               }
-               catch (IOException e)
-               {
-                  log.error(e.getLocalizedMessage());
-               }
+		    try {
+			for (int i = 0; i < values.size(); i++) {
+			    byte[] bytes = values.get(i).getAsByteArray();
+			    String val = new String(bytes,
+				    Constants.DEFAULT_ENCODING);
+			    if (val.equals(propertyValue)) {
+				return true;
+			    }
+			}
+		    } catch (IOException e) {
+			log.error(e.getLocalizedMessage());
+		    }
 
-            }
-            catch (RepositoryException e)
-            {
-               log.error(e.getLocalizedMessage());
-            }
-         }
-         return false;
-      }
-   }
+		} catch (RepositoryException e) {
+		    log.error(e.getLocalizedMessage());
+		}
+	    }
+	    return false;
+	}
+    }
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneQueryBuilder.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,21 +16,6 @@
  */
 package org.exoplatform.services.jcr.impl.core.query.lucene;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.jcr.NamespaceException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.query.InvalidQueryException;
-
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.queryParser.ParseException;
@@ -39,7 +24,6 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.exoplatform.commons.utils.ISO8601;
-import org.exoplatform.services.jcr.core.nodetype.NodeTypeData;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
 import org.exoplatform.services.jcr.dataflow.ItemDataConsumer;
 import org.exoplatform.services.jcr.datamodel.IllegalNameException;
@@ -51,7 +35,6 @@
 import org.exoplatform.services.jcr.datamodel.QPathEntry;
 import org.exoplatform.services.jcr.impl.Constants;
 import org.exoplatform.services.jcr.impl.core.LocationFactory;
-import org.exoplatform.services.jcr.impl.core.RepositoryImpl;
 import org.exoplatform.services.jcr.impl.core.SessionImpl;
 import org.exoplatform.services.jcr.impl.core.query.AndQueryNode;
 import org.exoplatform.services.jcr.impl.core.query.DefaultQueryNodeVisitor;
@@ -70,1221 +53,1151 @@
 import org.exoplatform.services.jcr.impl.core.query.QueryNodeVisitor;
 import org.exoplatform.services.jcr.impl.core.query.QueryRootNode;
 import org.exoplatform.services.jcr.impl.core.query.RelationQueryNode;
-import org.exoplatform.services.jcr.impl.core.query.SearchManager;
 import org.exoplatform.services.jcr.impl.core.query.TextsearchQueryNode;
-
 import org.exoplatform.services.jcr.impl.util.ISO9075;
 import org.exoplatform.services.jcr.impl.xml.XMLChar;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.query.InvalidQueryException;
+
 /**
- * Implements a query builder that takes an abstract query tree and creates
- * a lucene {@link org.apache.lucene.search.Query} tree that can be executed
- * on an index.
- * todo introduce a node type hierarchy for efficient translation of NodeTypeQueryNode
+ * Implements a query builder that takes an abstract query tree and creates a
+ * lucene {@link org.apache.lucene.search.Query} tree that can be executed on an
+ * index. todo introduce a node type hierarchy for efficient translation of
+ * NodeTypeQueryNode
  */
-public class LuceneQueryBuilder implements QueryNodeVisitor
-{
-   /**
-    * Namespace URI for xpath functions
-    */
-   private static final String NS_FN_PREFIX = "fn";
+public class LuceneQueryBuilder implements QueryNodeVisitor {
+    /**
+     * Namespace URI for xpath functions
+     */
+    private static final String NS_FN_PREFIX = "fn";
 
-   public static final String NS_FN_URI = "http://www.w3.org/2005/xpath-functions";
+    public static final String NS_FN_URI = "http://www.w3.org/2005/xpath-functions";
 
-   /**
-    * Deprecated namespace URI for xpath functions
-    */
-   private static final String NS_FN_OLD_PREFIX = "fn_old";
+    /**
+     * Deprecated namespace URI for xpath functions
+     */
+    private static final String NS_FN_OLD_PREFIX = "fn_old";
 
-   public static final String NS_FN_OLD_URI = "http://www.w3.org/2004/10/xpath-functions";
+    public static final String NS_FN_OLD_URI = "http://www.w3.org/2004/10/xpath-functions";
 
-   /**
-    * Namespace URI for XML schema
-    */
-   private static final String NS_XS_PREFIX = "xs";
+    /**
+     * Namespace URI for XML schema
+     */
+    private static final String NS_XS_PREFIX = "xs";
 
-   public static final String NS_XS_URI = "http://www.w3.org/2001/XMLSchema";
+    public static final String NS_XS_URI = "http://www.w3.org/2001/XMLSchema";
 
-   /**
-    * Logger for this class
-    */
-   private static final Logger log = LoggerFactory.getLogger(LuceneQueryBuilder.class);
+    /**
+     * Logger for this class
+     */
+    private static final Logger log = LoggerFactory
+	    .getLogger(LuceneQueryBuilder.class);
 
-   /**
-    * Root node of the abstract query tree
-    */
-   private final QueryRootNode root;
+    /**
+     * Root node of the abstract query tree
+     */
+    private final QueryRootNode root;
 
-   /**
-    * Session of the user executing this query
-    */
-   private final SessionImpl session;
+    /**
+     * Session of the user executing this query
+     */
+    private final SessionImpl session;
 
-   /**
-    * The shared item state manager of the workspace.
-    */
-   private final ItemDataConsumer sharedItemMgr;
+    /**
+     * The shared item state manager of the workspace.
+     */
+    private final ItemDataConsumer sharedItemMgr;
 
-   //    /**
-   //     * A hierarchy manager based on {@link #sharedItemMgr} to resolve paths.
-   //     */
-   //    private final HierarchyManager hmgr;
+    // /**
+    // * A hierarchy manager based on {@link #sharedItemMgr} to resolve paths.
+    // */
+    // private final HierarchyManager hmgr;
 
-   /**
-    * Namespace mappings to internal prefixes
-    */
-   private final NamespaceMappings nsMappings;
+    /**
+     * Namespace mappings to internal prefixes
+     */
+    private final NamespaceMappings nsMappings;
 
-   /**
-    * Name and Path resolver
-    */
-   private final LocationFactory resolver;
+    /**
+     * Name and Path resolver
+     */
+    private final LocationFactory resolver;
 
-   /**
-    * The analyzer instance to use for contains function query parsing
-    */
-   private final Analyzer analyzer;
+    /**
+     * The analyzer instance to use for contains function query parsing
+     */
+    private final Analyzer analyzer;
 
-   /**
-    * The property type registry.
-    */
-   private final PropertyTypeRegistry propRegistry;
+    /**
+     * The property type registry.
+     */
+    private final PropertyTypeRegistry propRegistry;
 
-   /**
-    * The synonym provider or <code>null</code> if none is configured.
-    */
-   private final SynonymProvider synonymProvider;
+    /**
+     * The synonym provider or <code>null</code> if none is configured.
+     */
+    private final SynonymProvider synonymProvider;
 
-   /**
-    * Wether the index format is new or old.
-    */
-   private final IndexFormatVersion indexFormatVersion;
+    /**
+     * Wether the index format is new or old.
+     */
+    private final IndexFormatVersion indexFormatVersion;
 
-   /**
-    * Exceptions thrown during tree translation
-    */
-   private final List exceptions = new ArrayList();
+    /**
+     * Exceptions thrown during tree translation
+     */
+    private final List exceptions = new ArrayList();
 
-   private final NodeTypeDataManager nodeTypeDataManager;
+    private final NodeTypeDataManager nodeTypeDataManager;
 
-   /**
-    * Creates a new <code>LuceneQueryBuilder</code> instance.
-    *
-    * @param root               the root node of the abstract query tree.
-    * @param session            of the user executing this query.
-    * @param sharedItemMgr      the shared item state manager of the
-    *                           workspace.
-    * @param hmgr               a hierarchy manager based on sharedItemMgr.
-    * @param nsMappings         namespace resolver for internal prefixes.
-    * @param analyzer           for parsing the query statement of the contains
-    *                           function.
-    * @param propReg            the property type registry.
-    * @param synonymProvider    the synonym provider or <code>null</code> if
-    *                           node is configured.
-    * @param indexFormatVersion the index format version for the lucene query.
-   * @throws RepositoryException 
-    */
-   private LuceneQueryBuilder(QueryRootNode root, SessionImpl session, ItemDataConsumer sharedItemMgr,
-      //HierarchyManager hmgr,
-      NamespaceMappings nsMappings, Analyzer analyzer, PropertyTypeRegistry propReg, SynonymProvider synonymProvider,
-      IndexFormatVersion indexFormatVersion) throws RepositoryException
-   {
-      this.root = root;
-      this.session = session;
-      this.sharedItemMgr = sharedItemMgr;
-      //this.hmgr = hmgr;
-      this.nsMappings = nsMappings;
-      this.analyzer = analyzer;
-      this.propRegistry = propReg;
-      this.synonymProvider = synonymProvider;
-      this.indexFormatVersion = indexFormatVersion;
-      this.nodeTypeDataManager = session.getWorkspace().getNodeTypesHolder();
-      this.resolver = new LocationFactory(nsMappings);
-   }
+    private final VirtualTableResolver<Query> virtualTableResolver;
 
-   /**
-    * Creates a lucene {@link org.apache.lucene.search.Query} tree from an
-    * abstract query tree.
-    *
-    * @param root            the root node of the abstract query tree.
-    * @param session         of the user executing the query.
-    * @param sharedItemMgr   the shared item state manager of the workspace.
-    * @param nsMappings      namespace resolver for internal prefixes.
-    * @param analyzer        for parsing the query statement of the contains
-    *                        function.
-    * @param propReg         the property type registry to lookup type
-    *                        information.
-    * @param synonymProvider the synonym provider or <code>null</code> if node
-    *                        is configured.
-    * @param  indexFormatVersion  the index format version to be used
-    * @return the lucene query tree.
-    * @throws RepositoryException if an error occurs during the translation.
-    */
-   public static Query createQuery(QueryRootNode root, SessionImpl session, ItemDataConsumer sharedItemMgr,
-      NamespaceMappings nsMappings, Analyzer analyzer, PropertyTypeRegistry propReg, SynonymProvider synonymProvider,
-      IndexFormatVersion indexFormatVersion) throws RepositoryException
-   {
+    /**
+     * Creates a new <code>LuceneQueryBuilder</code> instance.
+     * 
+     * @param root
+     *            the root node of the abstract query tree.
+     * @param session
+     *            of the user executing this query.
+     * @param sharedItemMgr
+     *            the shared item state manager of the workspace.
+     * @param hmgr
+     *            a hierarchy manager based on sharedItemMgr.
+     * @param nsMappings
+     *            namespace resolver for internal prefixes.
+     * @param analyzer
+     *            for parsing the query statement of the contains function.
+     * @param propReg
+     *            the property type registry.
+     * @param synonymProvider
+     *            the synonym provider or <code>null</code> if node is
+     *            configured.
+     * @param indexFormatVersion
+     *            the index format version for the lucene query.
+     * @param virtualTableResolver
+     * @throws RepositoryException
+     */
+    private LuceneQueryBuilder(
+	    QueryRootNode root,
+	    SessionImpl session,
+	    ItemDataConsumer sharedItemMgr,
+	    // HierarchyManager hmgr,
+	    NamespaceMappings nsMappings, Analyzer analyzer,
+	    PropertyTypeRegistry propReg, SynonymProvider synonymProvider,
+	    IndexFormatVersion indexFormatVersion,
+	    VirtualTableResolver<Query> virtualTableResolver)
+	    throws RepositoryException {
+	this.root = root;
+	this.session = session;
+	this.sharedItemMgr = sharedItemMgr;
+	// this.hmgr = hmgr;
+	this.nsMappings = nsMappings;
+	this.analyzer = analyzer;
+	this.propRegistry = propReg;
+	this.synonymProvider = synonymProvider;
+	this.indexFormatVersion = indexFormatVersion;
+	this.virtualTableResolver = virtualTableResolver;
+	this.nodeTypeDataManager = session.getWorkspace().getNodeTypesHolder();
+	this.resolver = new LocationFactory(nsMappings);
+    }
 
-      LuceneQueryBuilder builder =
-         new LuceneQueryBuilder(root, session, sharedItemMgr, nsMappings, analyzer, propReg, synonymProvider,
-            indexFormatVersion);
+    /**
+     * Creates a lucene {@link org.apache.lucene.search.Query} tree from an
+     * abstract query tree.
+     * 
+     * @param root
+     *            the root node of the abstract query tree.
+     * @param session
+     *            of the user executing the query.
+     * @param sharedItemMgr
+     *            the shared item state manager of the workspace.
+     * @param nsMappings
+     *            namespace resolver for internal prefixes.
+     * @param analyzer
+     *            for parsing the query statement of the contains function.
+     * @param propReg
+     *            the property type registry to lookup type information.
+     * @param synonymProvider
+     *            the synonym provider or <code>null</code> if node is
+     *            configured.
+     * @param indexFormatVersion
+     *            the index format version to be used
+     * @return the lucene query tree.
+     * @throws RepositoryException
+     *             if an error occurs during the translation.
+     */
+    public static Query createQuery(QueryRootNode root, SessionImpl session,
+	    ItemDataConsumer sharedItemMgr, NamespaceMappings nsMappings,
+	    Analyzer analyzer, PropertyTypeRegistry propReg,
+	    SynonymProvider synonymProvider,
+	    IndexFormatVersion indexFormatVersion,
+	    VirtualTableResolver<Query> virtualTableResolver)
+	    throws RepositoryException {
 
-      Query q = builder.createLuceneQuery();
-      if (builder.exceptions.size() > 0)
-      {
-         StringBuffer msg = new StringBuffer();
-         for (Iterator it = builder.exceptions.iterator(); it.hasNext();)
-         {
-            msg.append(it.next().toString()).append('\n');
-         }
-         throw new RepositoryException("Exception building query: " + msg.toString());
-      }
-      return q;
-   }
+	LuceneQueryBuilder builder = new LuceneQueryBuilder(root, session,
+		sharedItemMgr, nsMappings, analyzer, propReg, synonymProvider,
+		indexFormatVersion, virtualTableResolver);
 
-   /**
-    * Starts the tree traversal and returns the lucene
-    * {@link org.apache.lucene.search.Query}.
-    *
-    * @return the lucene <code>Query</code>.
-    * @throws RepositoryException
-    */
-   private Query createLuceneQuery() throws RepositoryException
-   {
-      return (Query)root.accept(this, null);
-   }
+	Query q = builder.createLuceneQuery();
+	if (builder.exceptions.size() > 0) {
+	    StringBuffer msg = new StringBuffer();
+	    for (Iterator it = builder.exceptions.iterator(); it.hasNext();) {
+		msg.append(it.next().toString()).append('\n');
+	    }
+	    throw new RepositoryException("Exception building query: "
+		    + msg.toString());
+	}
+	return q;
+    }
 
-   //---------------------< QueryNodeVisitor interface >-----------------------
+    /**
+     * Starts the tree traversal and returns the lucene
+     * {@link org.apache.lucene.search.Query}.
+     * 
+     * @return the lucene <code>Query</code>.
+     * @throws RepositoryException
+     */
+    private Query createLuceneQuery() throws RepositoryException {
+	return (Query) root.accept(this, null);
+    }
 
-   public Object visit(QueryRootNode node, Object data) throws RepositoryException
-   {
-      BooleanQuery root = new BooleanQuery();
+    // ---------------------< QueryNodeVisitor interface
+    // >-----------------------
 
-      Query wrapped = root;
-      if (node.getLocationNode() != null)
-      {
-         wrapped = (Query)node.getLocationNode().accept(this, root);
-      }
+    public Object visit(QueryRootNode node, Object data)
+	    throws RepositoryException {
+	BooleanQuery root = new BooleanQuery();
 
-      return wrapped;
-   }
+	Query wrapped = root;
+	if (node.getLocationNode() != null) {
+	    wrapped = (Query) node.getLocationNode().accept(this, root);
+	}
 
-   public Object visit(OrQueryNode node, Object data) throws RepositoryException
-   {
-      BooleanQuery orQuery = new BooleanQuery();
-      Object[] result = node.acceptOperands(this, null);
-      for (int i = 0; i < result.length; i++)
-      {
-         Query operand = (Query)result[i];
-         orQuery.add(operand, Occur.SHOULD);
-      }
-      return orQuery;
-   }
+	return wrapped;
+    }
 
-   public Object visit(AndQueryNode node, Object data) throws RepositoryException
-   {
-      Object[] result = node.acceptOperands(this, null);
-      if (result.length == 0)
-      {
-         return null;
-      }
-      BooleanQuery andQuery = new BooleanQuery();
-      for (int i = 0; i < result.length; i++)
-      {
-         Query operand = (Query)result[i];
-         andQuery.add(operand, Occur.MUST);
-      }
-      return andQuery;
-   }
+    public Object visit(OrQueryNode node, Object data)
+	    throws RepositoryException {
+	BooleanQuery orQuery = new BooleanQuery();
+	Object[] result = node.acceptOperands(this, null);
+	for (int i = 0; i < result.length; i++) {
+	    Query operand = (Query) result[i];
+	    orQuery.add(operand, Occur.SHOULD);
+	}
+	return orQuery;
+    }
 
-   public Object visit(NotQueryNode node, Object data) throws RepositoryException
-   {
-      Object[] result = node.acceptOperands(this, null);
-      if (result.length == 0)
-      {
-         return data;
-      }
-      // join the results
-      BooleanQuery b = new BooleanQuery();
-      for (int i = 0; i < result.length; i++)
-      {
-         b.add((Query)result[i], Occur.SHOULD);
-      }
-      // negate
-      return new NotQuery(b);
-   }
+    public Object visit(AndQueryNode node, Object data)
+	    throws RepositoryException {
+	Object[] result = node.acceptOperands(this, null);
+	if (result.length == 0) {
+	    return null;
+	}
+	BooleanQuery andQuery = new BooleanQuery();
+	for (int i = 0; i < result.length; i++) {
+	    Query operand = (Query) result[i];
+	    andQuery.add(operand, Occur.MUST);
+	}
+	return andQuery;
+    }
 
-   public Object visit(ExactQueryNode node, Object data)
-   {
-      String field = "";
-      String value = "";
-      try
-      {
-         field = resolver.createJCRName(node.getPropertyName()).getAsString();
-         value = resolver.createJCRName(node.getValue()).getAsString();
-      }
-      catch (RepositoryException e)
-      {
-         // will never happen, prefixes are created when unknown
-      }
-      return new JackrabbitTermQuery(new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, value)));
-   }
+    public Object visit(NotQueryNode node, Object data)
+	    throws RepositoryException {
+	Object[] result = node.acceptOperands(this, null);
+	if (result.length == 0) {
+	    return data;
+	}
+	// join the results
+	BooleanQuery b = new BooleanQuery();
+	for (int i = 0; i < result.length; i++) {
+	    b.add((Query) result[i], Occur.SHOULD);
+	}
+	// negate
+	return new NotQuery(b);
+    }
 
-   public Object visit(NodeTypeQueryNode node, Object data)
-   {
+    public Object visit(ExactQueryNode node, Object data) {
+	String field = "";
+	String value = "";
+	try {
+	    field = resolver.createJCRName(node.getPropertyName())
+		    .getAsString();
+	    value = resolver.createJCRName(node.getValue()).getAsString();
+	} catch (RepositoryException e) {
+	    // will never happen, prefixes are created when unknown
+	}
+	return new JackrabbitTermQuery(new Term(FieldNames.PROPERTIES,
+		FieldNames.createNamedValue(field, value)));
+    }
 
-      List terms = new ArrayList();
-      try
-      {
-         String mixinTypesField = resolver.createJCRName(Constants.JCR_MIXINTYPES).getAsString();
-         String primaryTypeField = resolver.createJCRName(Constants.JCR_PRIMARYTYPE).getAsString();
+    public Object visit(NodeTypeQueryNode node, Object data) {
 
-         NodeTypeData base = nodeTypeDataManager.findNodeType(node.getValue());
+	try {
+	    return virtualTableResolver.resolve(node.getValue(), true);
+	} catch (InvalidQueryException e1) {
+	    exceptions.add(e1);
+	} catch (RepositoryException e1) {
+	    exceptions.add(e1);
+	}
+	return new BooleanQuery();
+	// // (result)
+	// List terms = new ArrayList();
+	// try {
+	// String mixinTypesField = resolver.createJCRName(
+	// Constants.JCR_MIXINTYPES).getAsString();
+	// String primaryTypeField = resolver.createJCRName(
+	// Constants.JCR_PRIMARYTYPE).getAsString();
+	//
+	// NodeTypeData base = nodeTypeDataManager.findNodeType(node
+	// .getValue());
+	//
+	// if (base.isMixin()) {
+	// // search for nodes where jcr:mixinTypes is set to this mixin
+	// Term t = new Term(FieldNames.PROPERTIES, FieldNames
+	// .createNamedValue(mixinTypesField, resolver
+	// .createJCRName(node.getValue()).getAsString()));
+	// terms.add(t);
+	// } else {
+	// // search for nodes where jcr:primaryType is set to this type
+	// Term t = new Term(FieldNames.PROPERTIES, FieldNames
+	// .createNamedValue(primaryTypeField, resolver
+	// .createJCRName(node.getValue()).getAsString()));
+	// terms.add(t);
+	// }
+	//
+	// // now search for all node types that are derived from base
+	// Collection<NodeTypeData> allTypes = nodeTypeDataManager
+	// .getAllNodeTypes();
+	// for (NodeTypeData nodeTypeData : allTypes) {
+	// InternalQName[] superTypes = nodeTypeData
+	// .getDeclaredSupertypeNames();
+	// if (Arrays.asList(superTypes).contains(base.getName())) {
+	// String ntName = nsMappings.translateName(nodeTypeData
+	// .getName());
+	// Term t;
+	// if (nodeTypeData.isMixin()) {
+	// // search on jcr:mixinTypes
+	// t = new Term(FieldNames.PROPERTIES, FieldNames
+	// .createNamedValue(mixinTypesField, ntName));
+	// } else {
+	// // search on jcr:primaryType
+	// t = new Term(FieldNames.PROPERTIES, FieldNames
+	// .createNamedValue(primaryTypeField, ntName));
+	// }
+	// terms.add(t);
+	// }
+	// }
+	// } catch (IllegalNameException e) {
+	// exceptions.add(e);
+	// } catch (RepositoryException e) {
+	// exceptions.add(e);
+	// }
+	// if (terms.size() == 0) {
+	// // exception occured
+	// return new BooleanQuery();
+	// } else if (terms.size() == 1) {
+	// return new JackrabbitTermQuery((Term) terms.get(0));
+	// } else {
+	// BooleanQuery b = new BooleanQuery();
+	// for (Iterator it = terms.iterator(); it.hasNext();) {
+	// b.add(new JackrabbitTermQuery((Term) it.next()), Occur.SHOULD);
+	// }
+	// return b;
+	// }
+    }
 
-         if (base.isMixin())
-         {
-            // search for nodes where jcr:mixinTypes is set to this mixin
-            Term t =
-               new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(mixinTypesField, resolver.createJCRName(
-                  node.getValue()).getAsString()));
-            terms.add(t);
-         }
-         else
-         {
-            // search for nodes where jcr:primaryType is set to this type
-            Term t =
-               new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(primaryTypeField, resolver.createJCRName(
-                  node.getValue()).getAsString()));
-            terms.add(t);
-         }
+    public Object visit(TextsearchQueryNode node, Object data) {
+	try {
+	    QPath relPath = node.getRelativePath();
+	    String fieldname;
+	    if (relPath == null || !node.getReferencesProperty()) {
+		// fulltext on node
+		fieldname = FieldNames.FULLTEXT;
+	    } else {
+		// final path element is a property name
 
-         // now search for all node types that are derived from base
-         Collection<NodeTypeData> allTypes = nodeTypeDataManager.getAllNodeTypes();
-         for (NodeTypeData nodeTypeData : allTypes)
-         {
-            InternalQName[] superTypes = nodeTypeData.getDeclaredSupertypeNames();
-            if (Arrays.asList(superTypes).contains(base.getName()))
-            {
-               String ntName = nsMappings.translateName(nodeTypeData.getName());
-               Term t;
-               if (nodeTypeData.isMixin())
-               {
-                  // search on jcr:mixinTypes
-                  t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(mixinTypesField, ntName));
-               }
-               else
-               {
-                  // search on jcr:primaryType
-                  t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(primaryTypeField, ntName));
-               }
-               terms.add(t);
-            }
-         }
-      }
-      catch (IllegalNameException e)
-      {
-         exceptions.add(e);
-      }
-      catch (RepositoryException e)
-      {
-         exceptions.add(e);
-      }
-      if (terms.size() == 0)
-      {
-         // exception occured
-         return new BooleanQuery();
-      }
-      else if (terms.size() == 1)
-      {
-         return new JackrabbitTermQuery((Term)terms.get(0));
-      }
-      else
-      {
-         BooleanQuery b = new BooleanQuery();
-         for (Iterator it = terms.iterator(); it.hasNext();)
-         {
-            b.add(new JackrabbitTermQuery((Term)it.next()), Occur.SHOULD);
-         }
-         return b;
-      }
-   }
+		fieldname = resolver.createJCRName(relPath.getName())
+			.getAsString();
+		int idx = fieldname.indexOf(':');
+		fieldname = fieldname.substring(0, idx + 1)
+			+ FieldNames.FULLTEXT_PREFIX
+			+ fieldname.substring(idx + 1);
 
-   public Object visit(TextsearchQueryNode node, Object data)
-   {
-      try
-      {
-         QPath relPath = node.getRelativePath();
-         String fieldname;
-         if (relPath == null || !node.getReferencesProperty())
-         {
-            // fulltext on node
-            fieldname = FieldNames.FULLTEXT;
-         }
-         else
-         {
-            // final path element is a property name
+	    }
+	    QueryParser parser = new JackrabbitQueryParser(fieldname, analyzer,
+		    synonymProvider);
+	    Query context = parser.parse(node.getQuery());
+	    if (relPath != null
+		    && (!node.getReferencesProperty() || relPath.getEntries().length > 1)) {
+		// text search on some child axis
+		QPathEntry[] elements = relPath.getEntries();
+		for (int i = elements.length - 1; i >= 0; i--) {
+		    QPathEntry name = null;
+		    if (!elements[i].equals(RelationQueryNode.STAR_NAME_TEST)) {
+			name = elements[i];
+		    }
+		    // join text search with name test
+		    // if path references property that's elements.length - 2
+		    // if path references node that's elements.length - 1
+		    if (name != null
+			    && ((node.getReferencesProperty() && i == elements.length - 2) || (!node
+				    .getReferencesProperty() && i == elements.length - 1))) {
+			Query q = new NameQuery(name, indexFormatVersion,
+				nsMappings);
+			BooleanQuery and = new BooleanQuery();
+			and.add(q, Occur.MUST);
+			and.add(context, Occur.MUST);
+			context = and;
+		    } else if ((node.getReferencesProperty() && i < elements.length - 2)
+			    || (!node.getReferencesProperty() && i < elements.length - 1)) {
+			// otherwise do a parent axis step
+			context = new ParentAxisQuery(context, name,
+				indexFormatVersion, nsMappings);
+		    }
+		}
+		// finally select parent
+		context = new ParentAxisQuery(context, null,
+			indexFormatVersion, nsMappings);
+	    }
+	    return context;
+	} catch (NamespaceException e) {
+	    exceptions.add(e);
+	} catch (ParseException e) {
+	    exceptions.add(e);
+	} catch (RepositoryException e) {
+	    // TODO Auto-generated catch block
+	    e.printStackTrace();
+	}
+	return null;
+    }
 
-            fieldname = resolver.createJCRName(relPath.getName()).getAsString(); 
-            int idx = fieldname.indexOf(':');
-            fieldname = fieldname.substring(0, idx + 1)
-                    + FieldNames.FULLTEXT_PREFIX + fieldname.substring(idx + 1);
-            
-         }
-         QueryParser parser = new JackrabbitQueryParser(fieldname, analyzer, synonymProvider);
-         Query context = parser.parse(node.getQuery());
-         if (relPath != null && (!node.getReferencesProperty() || relPath.getEntries().length > 1))
-         {
-            // text search on some child axis
-            QPathEntry[] elements = relPath.getEntries();
-            for (int i = elements.length - 1; i >= 0; i--)
-            {
-               QPathEntry name = null;
-               if (!elements[i].equals(RelationQueryNode.STAR_NAME_TEST))
-               {
-                  name = elements[i];
-               }
-               // join text search with name test
-               // if path references property that's elements.length - 2
-               // if path references node that's elements.length - 1
-               if (name != null
-                  && ((node.getReferencesProperty() && i == elements.length - 2) || (!node.getReferencesProperty() && i == elements.length - 1)))
-               {
-                  Query q = new NameQuery(name, indexFormatVersion, nsMappings);
-                  BooleanQuery and = new BooleanQuery();
-                  and.add(q, Occur.MUST);
-                  and.add(context, Occur.MUST);
-                  context = and;
-               }
-               else if ((node.getReferencesProperty() && i < elements.length - 2)
-                  || (!node.getReferencesProperty() && i < elements.length - 1))
-               {
-                  // otherwise do a parent axis step
-                  context = new ParentAxisQuery(context, name, indexFormatVersion, nsMappings);
-               }
-            }
-            // finally select parent
-            context = new ParentAxisQuery(context, null, indexFormatVersion, nsMappings);
-         }
-         return context;
-      }
-      catch (NamespaceException e)
-      {
-         exceptions.add(e);
-      }
-      catch (ParseException e)
-      {
-         exceptions.add(e);
-      }
-      catch (RepositoryException e)
-      {
-         // TODO Auto-generated catch block
-         e.printStackTrace();
-      }
-      return null;
-   }
+    public Object visit(PathQueryNode node, Object data)
+	    throws RepositoryException {
+	Query context = null;
+	LocationStepQueryNode[] steps = node.getPathSteps();
+	if (steps.length > 0) {
+	    if (node.isAbsolute() && !steps[0].getIncludeDescendants()) {
+		// eat up first step
+		InternalQName nameTest = steps[0].getNameTest();
+		if (nameTest == null) {
+		    // this is equivalent to the root node
+		    context = new JackrabbitTermQuery(new Term(FieldNames.UUID,
+			    Constants.ROOT_UUID));
+		} else if (nameTest.getName().length() == 0) {
+		    // root node
+		    context = new JackrabbitTermQuery(new Term(FieldNames.UUID,
+			    Constants.ROOT_UUID));
+		} else {
+		    // then this is a node != the root node
+		    // will never match anything!
+		    BooleanQuery and = new BooleanQuery();
+		    and.add(new JackrabbitTermQuery(new Term(FieldNames.UUID,
+			    Constants.ROOT_UUID)), Occur.MUST);
+		    and.add(new NameQuery(nameTest, indexFormatVersion,
+			    nsMappings), Occur.MUST);
+		    context = and;
+		}
+		LocationStepQueryNode[] tmp = new LocationStepQueryNode[steps.length - 1];
+		System.arraycopy(steps, 1, tmp, 0, steps.length - 1);
+		steps = tmp;
+	    } else {
+		// path is 1) relative or 2) descendant-or-self
+		// use root node as context
+		context = new JackrabbitTermQuery(new Term(FieldNames.UUID,
+			Constants.ROOT_UUID));
+	    }
+	} else {
+	    exceptions.add(new InvalidQueryException(
+		    "Number of location steps must be > 0"));
+	}
+	// loop over steps
+	for (int i = 0; i < steps.length; i++) {
+	    context = (Query) steps[i].accept(this, context);
+	}
+	if (data instanceof BooleanQuery) {
+	    BooleanQuery constraint = (BooleanQuery) data;
+	    if (constraint.getClauses().length > 0) {
+		constraint.add(context, Occur.MUST);
+		context = constraint;
+	    }
+	}
+	return context;
+    }
 
-   public Object visit(PathQueryNode node, Object data) throws RepositoryException
-   {
-      Query context = null;
-      LocationStepQueryNode[] steps = node.getPathSteps();
-      if (steps.length > 0)
-      {
-         if (node.isAbsolute() && !steps[0].getIncludeDescendants())
-         {
-            // eat up first step
-            InternalQName nameTest = steps[0].getNameTest();
-            if (nameTest == null)
-            {
-               // this is equivalent to the root node
-               context = new JackrabbitTermQuery(new Term(FieldNames.UUID, Constants.ROOT_UUID));
-            }
-            else if (nameTest.getName().length() == 0)
-            {
-               // root node
-               context = new JackrabbitTermQuery(new Term(FieldNames.UUID, Constants.ROOT_UUID));
-            }
-            else
-            {
-               // then this is a node != the root node
-               // will never match anything!
-               BooleanQuery and = new BooleanQuery();
-               and.add(new JackrabbitTermQuery(new Term(FieldNames.UUID, Constants.ROOT_UUID)), Occur.MUST);
-               and.add(new NameQuery(nameTest, indexFormatVersion, nsMappings), Occur.MUST);
-               context = and;
-            }
-            LocationStepQueryNode[] tmp = new LocationStepQueryNode[steps.length - 1];
-            System.arraycopy(steps, 1, tmp, 0, steps.length - 1);
-            steps = tmp;
-         }
-         else
-         {
-            // path is 1) relative or 2) descendant-or-self
-            // use root node as context
-            context = new JackrabbitTermQuery(new Term(FieldNames.UUID, Constants.ROOT_UUID));
-         }
-      }
-      else
-      {
-         exceptions.add(new InvalidQueryException("Number of location steps must be > 0"));
-      }
-      // loop over steps
-      for (int i = 0; i < steps.length; i++)
-      {
-         context = (Query)steps[i].accept(this, context);
-      }
-      if (data instanceof BooleanQuery)
-      {
-         BooleanQuery constraint = (BooleanQuery)data;
-         if (constraint.getClauses().length > 0)
-         {
-            constraint.add(context, Occur.MUST);
-            context = constraint;
-         }
-      }
-      return context;
-   }
+    public Object visit(LocationStepQueryNode node, Object data)
+	    throws RepositoryException {
+	Query context = (Query) data;
+	BooleanQuery andQuery = new BooleanQuery();
 
-   public Object visit(LocationStepQueryNode node, Object data) throws RepositoryException
-   {
-      Query context = (Query)data;
-      BooleanQuery andQuery = new BooleanQuery();
+	if (context == null) {
+	    exceptions.add(new IllegalArgumentException("Unsupported query"));
+	}
 
-      if (context == null)
-      {
-         exceptions.add(new IllegalArgumentException("Unsupported query"));
-      }
+	// predicate on step?
+	Object[] predicates = node.acceptOperands(this, data);
+	for (int i = 0; i < predicates.length; i++) {
+	    andQuery.add((Query) predicates[i], Occur.MUST);
+	}
 
-      // predicate on step?
-      Object[] predicates = node.acceptOperands(this, data);
-      for (int i = 0; i < predicates.length; i++)
-      {
-         andQuery.add((Query)predicates[i], Occur.MUST);
-      }
+	// check for position predicate
+	QueryNode[] pred = node.getPredicates();
+	for (int i = 0; i < pred.length; i++) {
+	    if (pred[i].getType() == QueryNode.TYPE_RELATION) {
+		RelationQueryNode pos = (RelationQueryNode) pred[i];
+		if (pos.getValueType() == QueryConstants.TYPE_POSITION) {
+		    node.setIndex(pos.getPositionValue());
+		}
+	    }
+	}
 
-      // check for position predicate
-      QueryNode[] pred = node.getPredicates();
-      for (int i = 0; i < pred.length; i++)
-      {
-         if (pred[i].getType() == QueryNode.TYPE_RELATION)
-         {
-            RelationQueryNode pos = (RelationQueryNode)pred[i];
-            if (pos.getValueType() == QueryConstants.TYPE_POSITION)
-            {
-               node.setIndex(pos.getPositionValue());
-            }
-         }
-      }
+	NameQuery nameTest = null;
+	if (node.getNameTest() != null) {
+	    nameTest = new NameQuery(node.getNameTest(), indexFormatVersion,
+		    nsMappings);
+	}
 
-      NameQuery nameTest = null;
-      if (node.getNameTest() != null)
-      {
-         nameTest = new NameQuery(node.getNameTest(), indexFormatVersion, nsMappings);
-      }
+	if (node.getIncludeDescendants()) {
+	    if (nameTest != null) {
+		andQuery.add(new DescendantSelfAxisQuery(context, nameTest,
+			false), Occur.MUST);
+	    } else {
+		// descendant-or-self with nametest=*
+		if (predicates.length > 0) {
+		    // if we have a predicate attached, the condition acts as
+		    // the sub query.
 
-      if (node.getIncludeDescendants())
-      {
-         if (nameTest != null)
-         {
-            andQuery.add(new DescendantSelfAxisQuery(context, nameTest, false), Occur.MUST);
-         }
-         else
-         {
-            // descendant-or-self with nametest=*
-            if (predicates.length > 0)
-            {
-               // if we have a predicate attached, the condition acts as
-               // the sub query.
+		    // only use descendant axis if path is not //*
+		    // otherwise the query for the predicate can be used itself
+		    PathQueryNode pathNode = (PathQueryNode) node.getParent();
+		    if (pathNode.getPathSteps()[0] != node) {
+			Query subQuery = new DescendantSelfAxisQuery(context,
+				andQuery, false);
+			andQuery = new BooleanQuery();
+			andQuery.add(subQuery, Occur.MUST);
+		    }
+		} else {
+		    // todo this will traverse the whole index, optimize!
+		    // only use descendant axis if path is not //*
+		    PathQueryNode pathNode = (PathQueryNode) node.getParent();
+		    if (pathNode.getPathSteps()[0] != node) {
+			if (node.getIndex() == LocationStepQueryNode.NONE) {
+			    context = new DescendantSelfAxisQuery(context,
+				    false);
+			    andQuery.add(context, Occur.MUST);
+			} else {
+			    context = new DescendantSelfAxisQuery(context, true);
+			    andQuery
+				    .add(new ChildAxisQuery(sharedItemMgr,
+					    context, null, node.getIndex(),
+					    indexFormatVersion, nsMappings),
+					    Occur.MUST);
+			}
+		    } else {
+			andQuery.add(new MatchAllDocsQuery(), Occur.MUST);
+		    }
+		}
+	    }
+	} else {
+	    // name test
+	    if (nameTest != null) {
+		andQuery.add(new ChildAxisQuery(sharedItemMgr, context,
+			nameTest.getName(), node.getIndex(),
+			indexFormatVersion, nsMappings), Occur.MUST);
+	    } else {
+		// select child nodes
+		andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null,
+			node.getIndex(), indexFormatVersion, nsMappings),
+			Occur.MUST);
+	    }
+	}
 
-               // only use descendant axis if path is not //*
-               // otherwise the query for the predicate can be used itself
-               PathQueryNode pathNode = (PathQueryNode)node.getParent();
-               if (pathNode.getPathSteps()[0] != node)
-               {
-                  Query subQuery = new DescendantSelfAxisQuery(context, andQuery, false);
-                  andQuery = new BooleanQuery();
-                  andQuery.add(subQuery, Occur.MUST);
-               }
-            }
-            else
-            {
-               // todo this will traverse the whole index, optimize!
-               // only use descendant axis if path is not //*
-               PathQueryNode pathNode = (PathQueryNode)node.getParent();
-               if (pathNode.getPathSteps()[0] != node)
-               {
-                  if (node.getIndex() == LocationStepQueryNode.NONE)
-                  {
-                     context = new DescendantSelfAxisQuery(context, false);
-                     andQuery.add(context, Occur.MUST);
-                  }
-                  else
-                  {
-                     context = new DescendantSelfAxisQuery(context, true);
-                     andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex(), indexFormatVersion,
-                        nsMappings), Occur.MUST);
-                  }
-               }
-               else
-               {
-                  andQuery.add(new MatchAllDocsQuery(), Occur.MUST);
-               }
-            }
-         }
-      }
-      else
-      {
-         // name test
-         if (nameTest != null)
-         {
-            andQuery.add(new ChildAxisQuery(sharedItemMgr, context, nameTest.getName(), node.getIndex(),
-               indexFormatVersion, nsMappings), Occur.MUST);
-         }
-         else
-         {
-            // select child nodes
-            andQuery.add(new ChildAxisQuery(sharedItemMgr, context, null, node.getIndex(), indexFormatVersion,
-               nsMappings), Occur.MUST);
-         }
-      }
+	return andQuery;
+    }
 
-      return andQuery;
-   }
+    public Object visit(DerefQueryNode node, Object data)
+	    throws RepositoryException {
+	Query context = (Query) data;
+	if (context == null) {
+	    exceptions.add(new IllegalArgumentException("Unsupported query"));
+	}
 
-   public Object visit(DerefQueryNode node, Object data) throws RepositoryException
-   {
-      Query context = (Query)data;
-      if (context == null)
-      {
-         exceptions.add(new IllegalArgumentException("Unsupported query"));
-      }
+	try {
+	    String refProperty = resolver.createJCRName(node.getRefProperty())
+		    .getAsString();
 
-      try
-      {
-         String refProperty = resolver.createJCRName(node.getRefProperty()).getAsString();
+	    if (node.getIncludeDescendants()) {
+		Query refPropQuery = Util.createMatchAllQuery(refProperty,
+			indexFormatVersion);
+		context = new DescendantSelfAxisQuery(context, refPropQuery,
+			false);
+	    }
 
-         if (node.getIncludeDescendants())
-         {
-            Query refPropQuery = Util.createMatchAllQuery(refProperty, indexFormatVersion);
-            context = new DescendantSelfAxisQuery(context, refPropQuery, false);
-         }
+	    context = new DerefQuery(context, refProperty, node.getNameTest(),
+		    indexFormatVersion, nsMappings);
 
-         context = new DerefQuery(context, refProperty, node.getNameTest(), indexFormatVersion, nsMappings);
+	    // attach predicates
+	    Object[] predicates = node.acceptOperands(this, data);
+	    if (predicates.length > 0) {
+		BooleanQuery andQuery = new BooleanQuery();
+		for (int i = 0; i < predicates.length; i++) {
+		    andQuery.add((Query) predicates[i], Occur.MUST);
+		}
+		andQuery.add(context, Occur.MUST);
+		context = andQuery;
+	    }
 
-         // attach predicates
-         Object[] predicates = node.acceptOperands(this, data);
-         if (predicates.length > 0)
-         {
-            BooleanQuery andQuery = new BooleanQuery();
-            for (int i = 0; i < predicates.length; i++)
-            {
-               andQuery.add((Query)predicates[i], Occur.MUST);
-            }
-            andQuery.add(context, Occur.MUST);
-            context = andQuery;
-         }
+	} catch (NamespaceException e) {
+	    // should never happen
+	    exceptions.add(e);
+	}
 
-      }
-      catch (NamespaceException e)
-      {
-         // should never happen
-         exceptions.add(e);
-      }
+	return context;
+    }
 
-      return context;
-   }
+    public Object visit(RelationQueryNode node, Object data)
+	    throws RepositoryException {
+	Query query;
+	String[] stringValues = new String[1];
+	switch (node.getValueType()) {
+	case 0:
+	    // not set: either IS NULL or IS NOT NULL
+	    break;
+	case QueryConstants.TYPE_DATE:
+	    stringValues[0] = DateField.dateToString(node.getDateValue());
+	    break;
+	case QueryConstants.TYPE_DOUBLE:
+	    stringValues[0] = DoubleField.doubleToString(node.getDoubleValue());
+	    break;
+	case QueryConstants.TYPE_LONG:
+	    stringValues[0] = LongField.longToString(node.getLongValue());
+	    break;
+	case QueryConstants.TYPE_STRING:
+	    if (node.getOperation() == QueryConstants.OPERATION_EQ_GENERAL
+		    || node.getOperation() == QueryConstants.OPERATION_EQ_VALUE
+		    || node.getOperation() == QueryConstants.OPERATION_NE_GENERAL
+		    || node.getOperation() == QueryConstants.OPERATION_NE_VALUE) {
+		// only use coercing on non-range operations
+		InternalQName propertyName = node.getRelativePath().getName();
+		stringValues = getStringValues(propertyName, node
+			.getStringValue());
+	    } else {
+		stringValues[0] = node.getStringValue();
+	    }
+	    break;
+	case QueryConstants.TYPE_POSITION:
+	    // ignore position. is handled in the location step
+	    return null;
+	default:
+	    throw new IllegalArgumentException("Unknown relation type: "
+		    + node.getValueType());
+	}
 
-   public Object visit(RelationQueryNode node, Object data) throws RepositoryException
-   {
-      Query query;
-      String[] stringValues = new String[1];
-      switch (node.getValueType())
-      {
-         case 0 :
-            // not set: either IS NULL or IS NOT NULL
-            break;
-         case QueryConstants.TYPE_DATE :
-            stringValues[0] = DateField.dateToString(node.getDateValue());
-            break;
-         case QueryConstants.TYPE_DOUBLE :
-            stringValues[0] = DoubleField.doubleToString(node.getDoubleValue());
-            break;
-         case QueryConstants.TYPE_LONG :
-            stringValues[0] = LongField.longToString(node.getLongValue());
-            break;
-         case QueryConstants.TYPE_STRING :
-            if (node.getOperation() == QueryConstants.OPERATION_EQ_GENERAL
-               || node.getOperation() == QueryConstants.OPERATION_EQ_VALUE
-               || node.getOperation() == QueryConstants.OPERATION_NE_GENERAL
-               || node.getOperation() == QueryConstants.OPERATION_NE_VALUE)
-            {
-               // only use coercing on non-range operations
-               InternalQName propertyName = node.getRelativePath().getName();
-               stringValues = getStringValues(propertyName, node.getStringValue());
-            }
-            else
-            {
-               stringValues[0] = node.getStringValue();
-            }
-            break;
-         case QueryConstants.TYPE_POSITION :
-            // ignore position. is handled in the location step
-            return null;
-         default :
-            throw new IllegalArgumentException("Unknown relation type: " + node.getValueType());
-      }
+	if (node.getRelativePath() == null
+		&& node.getOperation() != QueryConstants.OPERATION_SIMILAR
+		&& node.getOperation() != QueryConstants.OPERATION_SPELLCHECK) {
+	    exceptions.add(new InvalidQueryException(
+		    "@* not supported in predicate"));
+	    return data;
+	}
 
-      if (node.getRelativePath() == null && node.getOperation() != QueryConstants.OPERATION_SIMILAR
-         && node.getOperation() != QueryConstants.OPERATION_SPELLCHECK)
-      {
-         exceptions.add(new InvalidQueryException("@* not supported in predicate"));
-         return data;
-      }
+	// get property transformation
+	final int[] transform = new int[] { TransformConstants.TRANSFORM_NONE };
+	node.acceptOperands(new DefaultQueryNodeVisitor() {
+	    public Object visit(PropertyFunctionQueryNode node, Object data) {
+		if (node.getFunctionName().equals(
+			PropertyFunctionQueryNode.LOWER_CASE)) {
+		    transform[0] = TransformConstants.TRANSFORM_LOWER_CASE;
+		} else if (node.getFunctionName().equals(
+			PropertyFunctionQueryNode.UPPER_CASE)) {
+		    transform[0] = TransformConstants.TRANSFORM_UPPER_CASE;
+		}
+		return data;
+	    }
+	}, null);
 
-      // get property transformation
-      final int[] transform = new int[]{TransformConstants.TRANSFORM_NONE};
-      node.acceptOperands(new DefaultQueryNodeVisitor()
-      {
-         public Object visit(PropertyFunctionQueryNode node, Object data)
-         {
-            if (node.getFunctionName().equals(PropertyFunctionQueryNode.LOWER_CASE))
-            {
-               transform[0] = TransformConstants.TRANSFORM_LOWER_CASE;
-            }
-            else if (node.getFunctionName().equals(PropertyFunctionQueryNode.UPPER_CASE))
-            {
-               transform[0] = TransformConstants.TRANSFORM_UPPER_CASE;
-            }
-            return data;
-         }
-      }, null);
+	QPath relPath = node.getRelativePath();
+	if (node.getOperation() == QueryConstants.OPERATION_SIMILAR) {
+	    // this is a bit ugly:
+	    // add the name of a dummy property because relPath actually
+	    // references a property. whereas the relPath of the similar
+	    // operation references a node
+	    relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
+	}
+	String field = "";
+	try {
+	    field = resolver.createJCRName(relPath.getName()).getAsString();
+	} catch (NamespaceException e) {
+	    // should never happen
+	    exceptions.add(e);
+	}
 
-      QPath relPath = node.getRelativePath();
-      if (node.getOperation() == QueryConstants.OPERATION_SIMILAR)
-      {
-         // this is a bit ugly:
-         // add the name of a dummy property because relPath actually
-         // references a property. whereas the relPath of the similar
-         // operation references a node
-         relPath = QPath.makeChildPath(relPath, Constants.JCR_PRIMARYTYPE);
-      }
-      String field = "";
-      try
-      {
-         field = resolver.createJCRName(relPath.getName()).getAsString();
-      }
-      catch (NamespaceException e)
-      {
-         // should never happen
-         exceptions.add(e);
-      }
+	// support for fn:name()
+	InternalQName propName = relPath.getName();
+	if (propName.getNamespace().equals(NS_FN_URI)
+		&& propName.getName().equals("name()")) {
+	    if (node.getValueType() != QueryConstants.TYPE_STRING) {
+		exceptions.add(new InvalidQueryException("Name function can "
+			+ "only be used in conjunction with a string literal"));
+		return data;
+	    }
+	    if (node.getOperation() != QueryConstants.OPERATION_EQ_VALUE
+		    && node.getOperation() != QueryConstants.OPERATION_EQ_GENERAL) {
+		exceptions
+			.add(new InvalidQueryException(
+				"Name function can "
+					+ "only be used in conjunction with an equals operator"));
+		return data;
+	    }
+	    // check if string literal is a valid XML Name
+	    if (XMLChar.isValidName(node.getStringValue())) {
+		// parse string literal as JCR Name
+		try {
+		    InternalQName n = session
+			    .getLocationFactory()
+			    .parseJCRName(ISO9075.decode(node.getStringValue()))
+			    .getInternalName();
+		    query = new NameQuery(n, indexFormatVersion, nsMappings);
+		} catch (RepositoryException e) {
+		    exceptions.add(e);
+		    return data;
+		}
+	    } else {
+		// will never match -> create dummy query
+		query = new BooleanQuery();
+	    }
+	} else {
+	    switch (node.getOperation()) {
+	    case QueryConstants.OPERATION_EQ_VALUE: // =
+	    case QueryConstants.OPERATION_EQ_GENERAL:
+		BooleanQuery or = new BooleanQuery();
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term t = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    Query q;
+		    if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+			q = new CaseTermQuery.Upper(t);
+		    } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+			q = new CaseTermQuery.Lower(t);
+		    } else {
+			q = new JackrabbitTermQuery(t);
+		    }
+		    or.add(q, Occur.SHOULD);
+		}
+		query = or;
+		if (node.getOperation() == QueryConstants.OPERATION_EQ_VALUE) {
+		    query = createSingleValueConstraint(or, field);
+		}
+		break;
+	    case QueryConstants.OPERATION_GE_VALUE: // >=
+	    case QueryConstants.OPERATION_GE_GENERAL:
+		or = new BooleanQuery();
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term lower = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    Term upper = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, "\uFFFF"));
+		    or.add(new RangeQuery(lower, upper, true, transform[0]),
+			    Occur.SHOULD);
+		}
+		query = or;
+		if (node.getOperation() == QueryConstants.OPERATION_GE_VALUE) {
+		    query = createSingleValueConstraint(or, field);
+		}
+		break;
+	    case QueryConstants.OPERATION_GT_VALUE: // >
+	    case QueryConstants.OPERATION_GT_GENERAL:
+		or = new BooleanQuery();
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term lower = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    Term upper = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, "\uFFFF"));
+		    or.add(new RangeQuery(lower, upper, false, transform[0]),
+			    Occur.SHOULD);
+		}
+		query = or;
+		if (node.getOperation() == QueryConstants.OPERATION_GT_VALUE) {
+		    query = createSingleValueConstraint(or, field);
+		}
+		break;
+	    case QueryConstants.OPERATION_LE_VALUE: // <=
+	    case QueryConstants.OPERATION_LE_GENERAL: // <=
+		or = new BooleanQuery();
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term lower = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, ""));
+		    Term upper = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    or.add(new RangeQuery(lower, upper, true, transform[0]),
+			    Occur.SHOULD);
+		}
+		query = or;
+		if (node.getOperation() == QueryConstants.OPERATION_LE_VALUE) {
+		    query = createSingleValueConstraint(query, field);
+		}
+		break;
+	    case QueryConstants.OPERATION_LIKE: // LIKE
+		// the like operation always has one string value.
+		// no coercing, see above
+		if (stringValues[0].equals("%")) {
+		    query = Util.createMatchAllQuery(field, indexFormatVersion);
+		} else {
+		    query = new WildcardQuery(FieldNames.PROPERTIES, field,
+			    stringValues[0], transform[0]);
+		}
+		break;
+	    case QueryConstants.OPERATION_LT_VALUE: // <
+	    case QueryConstants.OPERATION_LT_GENERAL:
+		or = new BooleanQuery();
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term lower = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, ""));
+		    Term upper = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    or.add(new RangeQuery(lower, upper, false, transform[0]),
+			    Occur.SHOULD);
+		}
+		query = or;
+		if (node.getOperation() == QueryConstants.OPERATION_LT_VALUE) {
+		    query = createSingleValueConstraint(or, field);
+		}
+		break;
+	    case QueryConstants.OPERATION_NE_VALUE: // !=
+		// match nodes with property 'field' that includes svp and mvp
+		BooleanQuery notQuery = new BooleanQuery();
+		notQuery.add(Util
+			.createMatchAllQuery(field, indexFormatVersion),
+			Occur.SHOULD);
+		// exclude all nodes where 'field' has the term in question
+		for (int i = 0; i < stringValues.length; i++) {
+		    Term t = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    Query q;
+		    if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+			q = new CaseTermQuery.Upper(t);
+		    } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+			q = new CaseTermQuery.Lower(t);
+		    } else {
+			q = new JackrabbitTermQuery(t);
+		    }
+		    notQuery.add(q, Occur.MUST_NOT);
+		}
+		// and exclude all nodes where 'field' is multi valued
+		notQuery.add(new JackrabbitTermQuery(new Term(FieldNames.MVP,
+			field)), Occur.MUST_NOT);
+		query = notQuery;
+		break;
+	    case QueryConstants.OPERATION_NE_GENERAL: // !=
+		// that's:
+		// all nodes with property 'field'
+		// minus the nodes that have a single property 'field' that is
+		// not equal to term in question
+		// minus the nodes that have a multi-valued property 'field' and
+		// all values are equal to term in question
+		notQuery = new BooleanQuery();
+		notQuery.add(Util
+			.createMatchAllQuery(field, indexFormatVersion),
+			Occur.SHOULD);
+		for (int i = 0; i < stringValues.length; i++) {
+		    // exclude the nodes that have the term and are single
+		    // valued
+		    Term t = new Term(FieldNames.PROPERTIES, FieldNames
+			    .createNamedValue(field, stringValues[i]));
+		    Query svp = new NotQuery(new JackrabbitTermQuery(new Term(
+			    FieldNames.MVP, field)));
+		    BooleanQuery and = new BooleanQuery();
+		    Query q;
+		    if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE) {
+			q = new CaseTermQuery.Upper(t);
+		    } else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE) {
+			q = new CaseTermQuery.Lower(t);
+		    } else {
+			q = new JackrabbitTermQuery(t);
+		    }
+		    and.add(q, Occur.MUST);
+		    and.add(svp, Occur.MUST);
+		    notQuery.add(and, Occur.MUST_NOT);
+		}
+		// todo above also excludes multi-valued properties that contain
+		// multiple instances of only stringValues. e.g. text={foo, foo}
+		query = notQuery;
+		break;
+	    case QueryConstants.OPERATION_NULL:
+		query = new NotQuery(Util.createMatchAllQuery(field,
+			indexFormatVersion));
+		break;
+	    case QueryConstants.OPERATION_SIMILAR:
+		String uuid = "x";
+		try {
+		    // throw new UnsupportedOperationException();
+		    QPath path = resolver.parseJCRPath(node.getStringValue())
+			    .getInternalPath();
+		    NodeData parent = (NodeData) sharedItemMgr
+			    .getItemData(Constants.ROOT_UUID);
 
-      // support for fn:name()
-      InternalQName propName = relPath.getName();
-      if (propName.getNamespace().equals(NS_FN_URI) && propName.getName().equals("name()"))
-      {
-         if (node.getValueType() != QueryConstants.TYPE_STRING)
-         {
-            exceptions.add(new InvalidQueryException("Name function can "
-               + "only be used in conjunction with a string literal"));
-            return data;
-         }
-         if (node.getOperation() != QueryConstants.OPERATION_EQ_VALUE
-            && node.getOperation() != QueryConstants.OPERATION_EQ_GENERAL)
-         {
-            exceptions.add(new InvalidQueryException("Name function can "
-               + "only be used in conjunction with an equals operator"));
-            return data;
-         }
-         // check if string literal is a valid XML Name
-         if (XMLChar.isValidName(node.getStringValue()))
-         {
-            // parse string literal as JCR Name
-            try
-            {
-               InternalQName n =
-                  session.getLocationFactory().parseJCRName(ISO9075.decode(node.getStringValue())).getInternalName();
-               query = new NameQuery(n, indexFormatVersion, nsMappings);
-            }
-            catch (RepositoryException e)
-            {
-               exceptions.add(e);
-               return data;
-            }
-         }
-         else
-         {
-            // will never match -> create dummy query
-            query = new BooleanQuery();
-         }
-      }
-      else
-      {
-         switch (node.getOperation())
-         {
-            case QueryConstants.OPERATION_EQ_VALUE : // =
-            case QueryConstants.OPERATION_EQ_GENERAL :
-               BooleanQuery or = new BooleanQuery();
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  Query q;
-                  if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE)
-                  {
-                     q = new CaseTermQuery.Upper(t);
-                  }
-                  else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE)
-                  {
-                     q = new CaseTermQuery.Lower(t);
-                  }
-                  else
-                  {
-                     q = new JackrabbitTermQuery(t);
-                  }
-                  or.add(q, Occur.SHOULD);
-               }
-               query = or;
-               if (node.getOperation() == QueryConstants.OPERATION_EQ_VALUE)
-               {
-                  query = createSingleValueConstraint(or, field);
-               }
-               break;
-            case QueryConstants.OPERATION_GE_VALUE : // >=
-            case QueryConstants.OPERATION_GE_GENERAL :
-               or = new BooleanQuery();
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
-                  or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
-               }
-               query = or;
-               if (node.getOperation() == QueryConstants.OPERATION_GE_VALUE)
-               {
-                  query = createSingleValueConstraint(or, field);
-               }
-               break;
-            case QueryConstants.OPERATION_GT_VALUE : // >
-            case QueryConstants.OPERATION_GT_GENERAL :
-               or = new BooleanQuery();
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, "\uFFFF"));
-                  or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
-               }
-               query = or;
-               if (node.getOperation() == QueryConstants.OPERATION_GT_VALUE)
-               {
-                  query = createSingleValueConstraint(or, field);
-               }
-               break;
-            case QueryConstants.OPERATION_LE_VALUE : // <=
-            case QueryConstants.OPERATION_LE_GENERAL : // <=
-               or = new BooleanQuery();
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
-                  Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  or.add(new RangeQuery(lower, upper, true, transform[0]), Occur.SHOULD);
-               }
-               query = or;
-               if (node.getOperation() == QueryConstants.OPERATION_LE_VALUE)
-               {
-                  query = createSingleValueConstraint(query, field);
-               }
-               break;
-            case QueryConstants.OPERATION_LIKE : // LIKE
-               // the like operation always has one string value.
-               // no coercing, see above
-               if (stringValues[0].equals("%"))
-               {
-                  query = Util.createMatchAllQuery(field, indexFormatVersion);
-               }
-               else
-               {
-                  query = new WildcardQuery(FieldNames.PROPERTIES, field, stringValues[0], transform[0]);
-               }
-               break;
-            case QueryConstants.OPERATION_LT_VALUE : // <
-            case QueryConstants.OPERATION_LT_GENERAL :
-               or = new BooleanQuery();
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term lower = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, ""));
-                  Term upper = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  or.add(new RangeQuery(lower, upper, false, transform[0]), Occur.SHOULD);
-               }
-               query = or;
-               if (node.getOperation() == QueryConstants.OPERATION_LT_VALUE)
-               {
-                  query = createSingleValueConstraint(or, field);
-               }
-               break;
-            case QueryConstants.OPERATION_NE_VALUE : // !=
-               // match nodes with property 'field' that includes svp and mvp
-               BooleanQuery notQuery = new BooleanQuery();
-               notQuery.add(Util.createMatchAllQuery(field, indexFormatVersion), Occur.SHOULD);
-               // exclude all nodes where 'field' has the term in question
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  Query q;
-                  if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE)
-                  {
-                     q = new CaseTermQuery.Upper(t);
-                  }
-                  else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE)
-                  {
-                     q = new CaseTermQuery.Lower(t);
-                  }
-                  else
-                  {
-                     q = new JackrabbitTermQuery(t);
-                  }
-                  notQuery.add(q, Occur.MUST_NOT);
-               }
-               // and exclude all nodes where 'field' is multi valued
-               notQuery.add(new JackrabbitTermQuery(new Term(FieldNames.MVP, field)), Occur.MUST_NOT);
-               query = notQuery;
-               break;
-            case QueryConstants.OPERATION_NE_GENERAL : // !=
-               // that's:
-               // all nodes with property 'field'
-               // minus the nodes that have a single property 'field' that is
-               //    not equal to term in question
-               // minus the nodes that have a multi-valued property 'field' and
-               //    all values are equal to term in question
-               notQuery = new BooleanQuery();
-               notQuery.add(Util.createMatchAllQuery(field, indexFormatVersion), Occur.SHOULD);
-               for (int i = 0; i < stringValues.length; i++)
-               {
-                  // exclude the nodes that have the term and are single valued
-                  Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
-                  Query svp = new NotQuery(new JackrabbitTermQuery(new Term(FieldNames.MVP, field)));
-                  BooleanQuery and = new BooleanQuery();
-                  Query q;
-                  if (transform[0] == TransformConstants.TRANSFORM_UPPER_CASE)
-                  {
-                     q = new CaseTermQuery.Upper(t);
-                  }
-                  else if (transform[0] == TransformConstants.TRANSFORM_LOWER_CASE)
-                  {
-                     q = new CaseTermQuery.Lower(t);
-                  }
-                  else
-                  {
-                     q = new JackrabbitTermQuery(t);
-                  }
-                  and.add(q, Occur.MUST);
-                  and.add(svp, Occur.MUST);
-                  notQuery.add(and, Occur.MUST_NOT);
-               }
-               // todo above also excludes multi-valued properties that contain
-               //      multiple instances of only stringValues. e.g. text={foo, foo}
-               query = notQuery;
-               break;
-            case QueryConstants.OPERATION_NULL :
-               query = new NotQuery(Util.createMatchAllQuery(field, indexFormatVersion));
-               break;
-            case QueryConstants.OPERATION_SIMILAR :
-               String uuid = "x";
-               try
-               {
-                  // throw new UnsupportedOperationException();
-                  QPath path = resolver.parseJCRPath(node.getStringValue()).getInternalPath();
-                  NodeData parent = (NodeData)sharedItemMgr.getItemData(Constants.ROOT_UUID);
+		    if (path.equals(Constants.ROOT_PATH)) {
+			uuid = Constants.ROOT_UUID;
+		    } else {
+			QPathEntry[] relPathEntries = path.getRelPath(path
+				.getDepth());
+			ItemData item = parent;
+			for (int i = 0; i < relPathEntries.length; i++) {
+			    item = sharedItemMgr.getItemData(parent,
+				    relPathEntries[i]);
 
-                  if (path.equals(Constants.ROOT_PATH))
-                  {
-                     uuid = Constants.ROOT_UUID;
-                  }
-                  else
-                  {
-                     QPathEntry[] relPathEntries = path.getRelPath(path.getDepth());
-                     ItemData item = parent;
-                     for (int i = 0; i < relPathEntries.length; i++)
-                     {
-                        item = sharedItemMgr.getItemData(parent, relPathEntries[i]);
+			    if (item == null)
+				break;
 
-                        if (item == null)
-                           break;
+			    if (item.isNode())
+				parent = (NodeData) item;
+			    else if (i < relPathEntries.length - 1)
+				throw new IllegalPathException(
+					"Path can not contains a property as the intermediate element");
+			}
+			uuid = item.getIdentifier();
+		    }
 
-                        if (item.isNode())
-                           parent = (NodeData)item;
-                        else if (i < relPathEntries.length - 1)
-                           throw new IllegalPathException(
-                              "Path can not contains a property as the intermediate element");
-                     }
-                     uuid = item.getIdentifier();
-                  }
+		} catch (RepositoryException e) {
+		    exceptions.add(e);
+		}
+		query = new SimilarityQuery(uuid, analyzer);
+		break;
+	    case QueryConstants.OPERATION_NOT_NULL:
+		query = Util.createMatchAllQuery(field, indexFormatVersion);
+		break;
+	    case QueryConstants.OPERATION_SPELLCHECK:
+		query = Util.createMatchAllQuery(field, indexFormatVersion);
+		break;
+	    default:
+		throw new IllegalArgumentException(
+			"Unknown relation operation: " + node.getOperation());
+	    }
+	}
 
-               }
-               catch (RepositoryException e)
-               {
-                  exceptions.add(e);
-               }
-               query = new SimilarityQuery(uuid, analyzer);
-               break;
-            case QueryConstants.OPERATION_NOT_NULL :
-               query = Util.createMatchAllQuery(field, indexFormatVersion);
-               break;
-            case QueryConstants.OPERATION_SPELLCHECK :
-               query = Util.createMatchAllQuery(field, indexFormatVersion);
-               break;
-            default :
-               throw new IllegalArgumentException("Unknown relation operation: " + node.getOperation());
-         }
-      }
+	if (relPath.getEntries().length > 1) {
+	    // child axis in relation
+	    QPathEntry[] elements = relPath.getEntries();
+	    // elements.length - 1 = property name
+	    // elements.length - 2 = last child axis name test
+	    for (int i = elements.length - 2; i >= 0; i--) {
+		QPathEntry name = null;
+		if (!elements[i].equals(RelationQueryNode.STAR_NAME_TEST)) {
+		    name = elements[i];
+		}
+		if (i == elements.length - 2) {
+		    // join name test with property query if there is one
+		    if (name != null) {
+			Query nameTest = new NameQuery(name,
+				indexFormatVersion, nsMappings);
+			BooleanQuery and = new BooleanQuery();
+			and.add(query, Occur.MUST);
+			and.add(nameTest, Occur.MUST);
+			query = and;
+		    } else {
+			// otherwise the query can be used as is
+		    }
+		} else {
+		    query = new ParentAxisQuery(query, name,
+			    indexFormatVersion, nsMappings);
+		}
+	    }
+	    // finally select the parent of the selected nodes
+	    query = new ParentAxisQuery(query, null, indexFormatVersion,
+		    nsMappings);
+	}
 
-      if (relPath.getEntries().length > 1)
-      {
-         // child axis in relation
-         QPathEntry[] elements = relPath.getEntries();
-         // elements.length - 1 = property name
-         // elements.length - 2 = last child axis name test
-         for (int i = elements.length - 2; i >= 0; i--)
-         {
-            QPathEntry name = null;
-            if (!elements[i].equals(RelationQueryNode.STAR_NAME_TEST))
-            {
-               name = elements[i];
-            }
-            if (i == elements.length - 2)
-            {
-               // join name test with property query if there is one
-               if (name != null)
-               {
-                  Query nameTest = new NameQuery(name, indexFormatVersion, nsMappings);
-                  BooleanQuery and = new BooleanQuery();
-                  and.add(query, Occur.MUST);
-                  and.add(nameTest, Occur.MUST);
-                  query = and;
-               }
-               else
-               {
-                  // otherwise the query can be used as is
-               }
-            }
-            else
-            {
-               query = new ParentAxisQuery(query, name, indexFormatVersion, nsMappings);
-            }
-         }
-         // finally select the parent of the selected nodes
-         query = new ParentAxisQuery(query, null, indexFormatVersion, nsMappings);
-      }
+	return query;
+    }
 
-      return query;
-   }
+    public Object visit(OrderQueryNode node, Object data) {
+	return data;
+    }
 
-   public Object visit(OrderQueryNode node, Object data)
-   {
-      return data;
-   }
+    public Object visit(PropertyFunctionQueryNode node, Object data) {
+	return data;
+    }
 
-   public Object visit(PropertyFunctionQueryNode node, Object data)
-   {
-      return data;
-   }
+    // ---------------------------< internal
+    // >-----------------------------------
 
-   //---------------------------< internal >-----------------------------------
+    /**
+     * Wraps a constraint query around <code>q</code> that limits the nodes to
+     * those where <code>propName</code> is the name of a single value property
+     * on the node instance.
+     * 
+     * @param q
+     *            the query to wrap.
+     * @param propName
+     *            the name of a property that only has one value.
+     * @return the wrapped query <code>q</code>.
+     */
+    private Query createSingleValueConstraint(Query q, String propName) {
+	// get nodes with multi-values in propName
+	Query mvp = new JackrabbitTermQuery(new Term(FieldNames.MVP, propName));
+	// now negate, that gives the nodes that have propName as single
+	// values but also all others
+	Query svp = new NotQuery(mvp);
+	// now join the two, which will result in those nodes where propName
+	// only contains a single value. This works because q already restricts
+	// the result to those nodes that have a property propName
+	BooleanQuery and = new BooleanQuery();
+	and.add(q, Occur.MUST);
+	and.add(svp, Occur.MUST);
+	return and;
+    }
 
-   /**
-    * Wraps a constraint query around <code>q</code> that limits the nodes to
-    * those where <code>propName</code> is the name of a single value property
-    * on the node instance.
-    *
-    * @param q        the query to wrap.
-    * @param propName the name of a property that only has one value.
-    * @return the wrapped query <code>q</code>.
-    */
-   private Query createSingleValueConstraint(Query q, String propName)
-   {
-      // get nodes with multi-values in propName
-      Query mvp = new JackrabbitTermQuery(new Term(FieldNames.MVP, propName));
-      // now negate, that gives the nodes that have propName as single
-      // values but also all others
-      Query svp = new NotQuery(mvp);
-      // now join the two, which will result in those nodes where propName
-      // only contains a single value. This works because q already restricts
-      // the result to those nodes that have a property propName
-      BooleanQuery and = new BooleanQuery();
-      and.add(q, Occur.MUST);
-      and.add(svp, Occur.MUST);
-      return and;
-   }
+    /**
+     * Returns an array of String values to be used as a term to lookup the
+     * search index for a String <code>literal</code> of a certain property
+     * name. This method will lookup the <code>propertyName</code> in the node
+     * type registry trying to find out the {@link javax.jcr.PropertyType}s. If
+     * no property type is found looking up node type information, this method
+     * will guess the property type.
+     * 
+     * @param propertyName
+     *            the name of the property in the relation.
+     * @param literal
+     *            the String literal in the relation.
+     * @return the String values to use as term for the query.
+     */
+    private String[] getStringValues(InternalQName propertyName, String literal) {
+	PropertyTypeRegistry.TypeMapping[] types = propRegistry
+		.getPropertyTypes(propertyName);
+	List<String> values = new ArrayList<String>();
+	for (int i = 0; i < types.length; i++) {
+	    switch (types[i].type) {
+	    case PropertyType.NAME:
+		// try to translate name
+		try {
+		    InternalQName n = session.getLocationFactory()
+			    .parseJCRName(literal).getInternalName();
+		    values.add(nsMappings.translateName(n));
+		    log.debug("Coerced " + literal + " into NAME.");
+		} catch (RepositoryException e) {
+		    log.warn("Unable to coerce '" + literal + "' into a NAME: "
+			    + e.toString());
+		} catch (IllegalNameException e) {
+		    log.warn("Unable to coerce '" + literal + "' into a NAME: "
+			    + e.toString());
+		}
+		break;
+	    case PropertyType.PATH:
+		// try to translate path
+		try {
+		    QPath p = session.getLocationFactory()
+			    .parseJCRPath(literal).getInternalPath();
+		    values.add(resolver.createJCRPath(p).getAsString(true));
+		    log.debug("Coerced " + literal + " into PATH.");
+		} catch (RepositoryException e) {
+		    log.warn("Unable to coerce '" + literal + "' into a PATH: "
+			    + e.toString());
+		}
+		break;
+	    case PropertyType.DATE:
+		// try to parse date
+		Calendar c = ISO8601.parse(literal);
+		if (c != null) {
+		    values.add(DateField.timeToString(c.getTimeInMillis()));
+		    log.debug("Coerced " + literal + " into DATE.");
+		} else {
+		    log.warn("Unable to coerce '" + literal + "' into a DATE.");
+		}
+		break;
+	    case PropertyType.DOUBLE:
+		// try to parse double
+		try {
+		    double d = Double.parseDouble(literal);
+		    values.add(DoubleField.doubleToString(d));
+		    log.debug("Coerced " + literal + " into DOUBLE.");
+		} catch (NumberFormatException e) {
+		    log.warn("Unable to coerce '" + literal
+			    + "' into a DOUBLE: " + e.toString());
+		}
+		break;
+	    case PropertyType.LONG:
+		// try to parse long
+		try {
+		    long l = Long.parseLong(literal);
+		    values.add(LongField.longToString(l));
+		    log.debug("Coerced " + literal + " into LONG.");
+		} catch (NumberFormatException e) {
+		    log.warn("Unable to coerce '" + literal + "' into a LONG: "
+			    + e.toString());
+		}
+		break;
+	    case PropertyType.STRING:
+		values.add(literal);
+		log.debug("Using literal " + literal + " as is.");
+		break;
+	    }
+	}
+	if (values.size() == 0) {
+	    // use literal as is then try to guess other types
+	    values.add(literal);
 
-   /**
-    * Returns an array of String values to be used as a term to lookup the search index
-    * for a String <code>literal</code> of a certain property name. This method
-    * will lookup the <code>propertyName</code> in the node type registry
-    * trying to find out the {@link javax.jcr.PropertyType}s.
-    * If no property type is found looking up node type information, this
-    * method will guess the property type.
-    *
-    * @param propertyName the name of the property in the relation.
-    * @param literal      the String literal in the relation.
-    * @return the String values to use as term for the query.
-    */
-   private String[] getStringValues(InternalQName propertyName, String literal)
-   {
-      PropertyTypeRegistry.TypeMapping[] types = propRegistry.getPropertyTypes(propertyName);
-      List<String> values = new ArrayList<String>();
-      for (int i = 0; i < types.length; i++)
-      {
-         switch (types[i].type)
-         {
-            case PropertyType.NAME :
-               // try to translate name
-               try
-               {
-                  InternalQName n = session.getLocationFactory().parseJCRName(literal).getInternalName();
-                  values.add(nsMappings.translateName(n));
-                  log.debug("Coerced " + literal + " into NAME.");
-               }
-               catch (RepositoryException e)
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a NAME: " + e.toString());
-               }
-               catch (IllegalNameException e)
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a NAME: " + e.toString());
-               }
-               break;
-            case PropertyType.PATH :
-               // try to translate path
-               try
-               {
-                  QPath p = session.getLocationFactory().parseJCRPath(literal).getInternalPath();
-                  values.add(resolver.createJCRPath(p).getAsString(true));
-                  log.debug("Coerced " + literal + " into PATH.");
-               }
-               catch (RepositoryException e)
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a PATH: " + e.toString());
-               }
-               break;
-            case PropertyType.DATE :
-               // try to parse date
-               Calendar c = ISO8601.parse(literal);
-               if (c != null)
-               {
-                  values.add(DateField.timeToString(c.getTimeInMillis()));
-                  log.debug("Coerced " + literal + " into DATE.");
-               }
-               else
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a DATE.");
-               }
-               break;
-            case PropertyType.DOUBLE :
-               // try to parse double
-               try
-               {
-                  double d = Double.parseDouble(literal);
-                  values.add(DoubleField.doubleToString(d));
-                  log.debug("Coerced " + literal + " into DOUBLE.");
-               }
-               catch (NumberFormatException e)
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a DOUBLE: " + e.toString());
-               }
-               break;
-            case PropertyType.LONG :
-               // try to parse long
-               try
-               {
-                  long l = Long.parseLong(literal);
-                  values.add(LongField.longToString(l));
-                  log.debug("Coerced " + literal + " into LONG.");
-               }
-               catch (NumberFormatException e)
-               {
-                  log.warn("Unable to coerce '" + literal + "' into a LONG: " + e.toString());
-               }
-               break;
-            case PropertyType.STRING :
-               values.add(literal);
-               log.debug("Using literal " + literal + " as is.");
-               break;
-         }
-      }
-      if (values.size() == 0)
-      {
-         // use literal as is then try to guess other types
-         values.add(literal);
-
-         // try to guess property type
-         if (literal.indexOf('/') > -1)
-         {
-            // might be a path
-            try
-            {
-               QPath p = session.getLocationFactory().parseJCRPath(literal).getInternalPath();
-               values.add(resolver.createJCRPath(p).getAsString(true));
-               log.debug("Coerced " + literal + " into PATH.");
-            }
-            catch (Exception e)
-            {
-               // not a path
-            }
-         }
-         if (XMLChar.isValidName(literal))
-         {
-            // might be a name
-            try
-            {
-               InternalQName n = session.getLocationFactory().parseJCRName(literal).getInternalName();
-               values.add(nsMappings.translateName(n));
-               log.debug("Coerced " + literal + " into NAME.");
-            }
-            catch (Exception e)
-            {
-               // not a name
-            }
-         }
-         if (literal.indexOf(':') > -1)
-         {
-            // is it a date?
-            Calendar c = ISO8601.parse(literal);
-            if (c != null)
-            {
-               values.add(DateField.timeToString(c.getTimeInMillis()));
-               log.debug("Coerced " + literal + " into DATE.");
-            }
-         }
-         else
-         {
-            // long or double are possible at this point
-            try
-            {
-               values.add(LongField.longToString(Long.parseLong(literal)));
-               log.debug("Coerced " + literal + " into LONG.");
-            }
-            catch (NumberFormatException e)
-            {
-               // not a long
-               // try double
-               try
-               {
-                  values.add(DoubleField.doubleToString(Double.parseDouble(literal)));
-                  log.debug("Coerced " + literal + " into DOUBLE.");
-               }
-               catch (NumberFormatException e1)
-               {
-                  // not a double
-               }
-            }
-         }
-      }
-      // if still no values use literal as is
-      if (values.size() == 0)
-      {
-         values.add(literal);
-         log.debug("Using literal " + literal + " as is.");
-      }
-      return (String[])values.toArray(new String[values.size()]);
-   }
+	    // try to guess property type
+	    if (literal.indexOf('/') > -1) {
+		// might be a path
+		try {
+		    QPath p = session.getLocationFactory()
+			    .parseJCRPath(literal).getInternalPath();
+		    values.add(resolver.createJCRPath(p).getAsString(true));
+		    log.debug("Coerced " + literal + " into PATH.");
+		} catch (Exception e) {
+		    // not a path
+		}
+	    }
+	    if (XMLChar.isValidName(literal)) {
+		// might be a name
+		try {
+		    InternalQName n = session.getLocationFactory()
+			    .parseJCRName(literal).getInternalName();
+		    values.add(nsMappings.translateName(n));
+		    log.debug("Coerced " + literal + " into NAME.");
+		} catch (Exception e) {
+		    // not a name
+		}
+	    }
+	    if (literal.indexOf(':') > -1) {
+		// is it a date?
+		Calendar c = ISO8601.parse(literal);
+		if (c != null) {
+		    values.add(DateField.timeToString(c.getTimeInMillis()));
+		    log.debug("Coerced " + literal + " into DATE.");
+		}
+	    } else {
+		// long or double are possible at this point
+		try {
+		    values.add(LongField.longToString(Long.parseLong(literal)));
+		    log.debug("Coerced " + literal + " into LONG.");
+		} catch (NumberFormatException e) {
+		    // not a long
+		    // try double
+		    try {
+			values.add(DoubleField.doubleToString(Double
+				.parseDouble(literal)));
+			log.debug("Coerced " + literal + " into DOUBLE.");
+		    } catch (NumberFormatException e1) {
+			// not a double
+		    }
+		}
+	    }
+	}
+	// if still no values use literal as is
+	if (values.size() == 0) {
+	    values.add(literal);
+	    log.debug("Using literal " + literal + " as is.");
+	}
+	return (String[]) values.toArray(new String[values.size()]);
+    }
 }

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneVirtualTableResolver.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneVirtualTableResolver.java	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneVirtualTableResolver.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * 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 org.exoplatform.services.jcr.impl.core.query.lucene;
+
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.exoplatform.services.jcr.core.NamespaceAccessor;
+import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+import org.exoplatform.services.jcr.impl.Constants;
+import org.exoplatform.services.jcr.impl.core.LocationFactory;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.query.InvalidQueryException;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk at gmail.com">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34027 2009-07-15 23:26:43Z
+ *          aheritier $
+ */
+public class LuceneVirtualTableResolver extends
+	NodeTypeVirtualTableResolver<Query> {
+
+    private final LocationFactory locationFactory;
+
+    /**
+     * Class logger.
+     */
+    private final Log log = ExoLogger
+	    .getLogger(LuceneVirtualTableResolver.class);
+
+    private final String mixinTypesField;
+
+    private final String primaryTypeField;
+
+    /**
+     * @param nodeTypeDataManager
+     * @throws RepositoryException
+     */
+    public LuceneVirtualTableResolver(
+	    final NodeTypeDataManager nodeTypeDataManager,
+	    final NamespaceAccessor namespaceAccessor)
+	    throws RepositoryException {
+	super(nodeTypeDataManager);
+
+	locationFactory = new LocationFactory(namespaceAccessor);
+	mixinTypesField = locationFactory.createJCRName(
+		Constants.JCR_MIXINTYPES).getAsString();
+	primaryTypeField = locationFactory.createJCRName(
+		Constants.JCR_PRIMARYTYPE).getAsString();
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Query resolve(final InternalQName tableName,
+	    final boolean includeInheritedTables) throws InvalidQueryException,
+	    RepositoryException {
+
+	final List<Term> terms = new ArrayList<Term>();
+
+	Query query = null;
+	try {
+	    final String nodeTypeStringName = locationFactory.createJCRName(
+		    tableName).getAsString();
+
+	    if (isMixin(tableName)) {
+		// search for nodes where jcr:mixinTypes is set to this mixin
+		Term t = new Term(FieldNames.PROPERTIES, FieldNames
+			.createNamedValue(mixinTypesField, nodeTypeStringName));
+		terms.add(t);
+
+	    } else {
+		// search for nodes where jcr:primaryType is set to this type
+
+		Term t = new Term(FieldNames.PROPERTIES, FieldNames
+			.createNamedValue(primaryTypeField, nodeTypeStringName));
+		terms.add(t);
+	    }
+	    if (includeInheritedTables) {
+		// now search for all node types that are derived from base
+		final Set<InternalQName> allTypes = getSubTypes(tableName);
+		for (final InternalQName descendantNt : allTypes) {
+		    final String ntName = locationFactory.createJCRName(
+			    descendantNt).getAsString();
+
+		    Term t;
+		    if (isMixin(descendantNt)) {
+			// search on jcr:mixinTypes
+			t = new Term(FieldNames.PROPERTIES, FieldNames
+				.createNamedValue(mixinTypesField, ntName));
+		    } else {
+			// search on jcr:primaryType
+			t = new Term(FieldNames.PROPERTIES, FieldNames
+				.createNamedValue(primaryTypeField, ntName));
+		    }
+		    terms.add(t);
+		}
+	    }
+	} catch (final NoSuchNodeTypeException e) {
+	    throw new InvalidQueryException(e.getMessage(), e);
+	}
+
+	if (terms.size() == 0) {
+	    // exception occured
+	    query = new BooleanQuery();
+
+	} else if (terms.size() == 1) {
+	    query = new JackrabbitTermQuery(terms.get(0));
+
+	} else {
+	    final BooleanQuery b = new BooleanQuery();
+	    for (final Object element : terms) {
+		// b.add(new TermQuery((Term) element), Occur.SHOULD);
+		b.add(new JackrabbitTermQuery((Term) element), Occur.SHOULD);
+	    }
+	    query = b;
+	}
+
+	return query;
+    }
+}


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/LuceneVirtualTableResolver.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeTypeVirtualTableResolver.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeTypeVirtualTableResolver.java	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeTypeVirtualTableResolver.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * 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 org.exoplatform.services.jcr.impl.core.query.lucene;
+
+import org.exoplatform.services.jcr.core.nodetype.NodeTypeData;
+import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk at gmail.com">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34027 2009-07-15 23:26:43Z
+ *          aheritier $
+ */
+public abstract class NodeTypeVirtualTableResolver<Q> implements
+	VirtualTableResolver<Q> {
+    private final NodeTypeDataManager nodeTypeDataManager;
+
+    /**
+     * @param nodeTypeDataManager
+     */
+    public NodeTypeVirtualTableResolver(
+	    final NodeTypeDataManager nodeTypeDataManager) {
+	super();
+	this.nodeTypeDataManager = nodeTypeDataManager;
+    }
+
+    /**
+     * @param nodeTypeName
+     *            name.
+     * @return Returns all subtypes of node type <code>nodeTypeName</code> in
+     *         the node type inheritance hierarchy.
+     * @throws RepositoryException
+     */
+    protected Set<InternalQName> getSubTypes(final InternalQName nodeTypeName)
+	    throws RepositoryException {
+	return this.nodeTypeDataManager.getSubtypes(nodeTypeName);
+    }
+
+    /**
+     * @param nodeTypeName
+     *            name.
+     * @return true if node type with name <code>nodeTypeName</code> is mixin.
+     * @throws RepositoryException
+     */
+    protected boolean isMixin(final InternalQName nodeTypeName)
+	    throws RepositoryException {
+	final NodeTypeData nodeType = this.nodeTypeDataManager
+		.findNodeType(nodeTypeName);
+	if (nodeType == null) {
+	    throw new NoSuchNodeTypeException("Node type "
+		    + nodeTypeName.getAsString() + " not found");
+	}
+	return nodeType.isMixin();
+    }
+}


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/NodeTypeVirtualTableResolver.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/QueryImpl.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/QueryImpl.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/QueryImpl.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,15 +16,6 @@
  */
 package org.exoplatform.services.jcr.impl.core.query.lucene;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.PropertyDefinition;
-import javax.jcr.query.InvalidQueryException;
-import javax.jcr.query.QueryResult;
-
 import org.apache.lucene.search.Query;
 import org.exoplatform.services.jcr.core.nodetype.NodeTypeData;
 import org.exoplatform.services.jcr.core.nodetype.PropertyDefinitionData;
@@ -33,8 +24,6 @@
 import org.exoplatform.services.jcr.impl.Constants;
 import org.exoplatform.services.jcr.impl.core.SessionDataManager;
 import org.exoplatform.services.jcr.impl.core.SessionImpl;
-import org.exoplatform.services.jcr.impl.core.nodetype.NodeTypeImpl;
-import org.exoplatform.services.jcr.impl.core.nodetype.PropertyDefinitionImpl;
 import org.exoplatform.services.jcr.impl.core.query.AndQueryNode;
 import org.exoplatform.services.jcr.impl.core.query.DefaultQueryNodeVisitor;
 import org.exoplatform.services.jcr.impl.core.query.LocationStepQueryNode;
@@ -44,10 +33,17 @@
 import org.exoplatform.services.jcr.impl.core.query.QueryNodeFactory;
 import org.exoplatform.services.jcr.impl.core.query.QueryParser;
 import org.exoplatform.services.jcr.impl.core.query.QueryRootNode;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.QueryResult;
+
 /**
  * Implements the {@link org.apache.jackrabbit.core.query.ExecutableQuery}
  * interface.
@@ -62,7 +58,8 @@
     /**
      * The default selector name 's'.
      */
-    public static final InternalQName DEFAULT_SELECTOR_NAME = new InternalQName(Constants.NS_DEFAULT_URI,"s");
+    public static final InternalQName DEFAULT_SELECTOR_NAME = new InternalQName(
+	    Constants.NS_DEFAULT_URI, "s");
 
     /**
      * The root node of the query tree
@@ -71,135 +68,149 @@
 
     /**
      * Creates a new query instance from a query string.
-     *
-     * @param session   the session of the user executing this query.
-     * @param itemMgr   the item manager of the session executing this query.
-     * @param index     the search index.
-     * @param propReg   the property type registry.
-     * @param statement the query statement.
-     * @param language  the syntax of the query statement.
-     * @param factory   the query node factory.
-     * @throws InvalidQueryException if the query statement is invalid according
-     *                               to the specified <code>language</code>.
+     * 
+     * @param session
+     *            the session of the user executing this query.
+     * @param itemMgr
+     *            the item manager of the session executing this query.
+     * @param index
+     *            the search index.
+     * @param propReg
+     *            the property type registry.
+     * @param statement
+     *            the query statement.
+     * @param language
+     *            the syntax of the query statement.
+     * @param factory
+     *            the query node factory.
+     * @throws InvalidQueryException
+     *             if the query statement is invalid according to the specified
+     *             <code>language</code>.
      */
-    public QueryImpl(SessionImpl session,
-                SessionDataManager itemMgr,
-                     SearchIndex index,
-                     PropertyTypeRegistry propReg,
-                     String statement,
-                     String language,
-                     QueryNodeFactory factory) throws InvalidQueryException {
-        super(session, itemMgr, index, propReg);
-        // parse query according to language
-        // build query tree using the passed factory
-        //this.root = QueryParser.parse(statement, language, session, factory);
-        this.root = QueryParser.parse(statement, language, session.getLocationFactory(), factory);
+    public QueryImpl(SessionImpl session, SessionDataManager itemMgr,
+	    SearchIndex index, PropertyTypeRegistry propReg, String statement,
+	    String language, QueryNodeFactory factory)
+	    throws InvalidQueryException {
+	super(session, itemMgr, index, propReg);
+	// parse query according to language
+	// build query tree using the passed factory
+	// this.root = QueryParser.parse(statement, language, session, factory);
+	this.root = QueryParser.parse(statement, language, session
+		.getLocationFactory(), factory);
     }
 
     /**
      * Executes this query and returns a <code>{@link QueryResult}</code>.
-     *
-     * @param offset the offset in the total result set
-     * @param limit the maximum result size
+     * 
+     * @param offset
+     *            the offset in the total result set
+     * @param limit
+     *            the maximum result size
      * @return a <code>QueryResult</code>
-     * @throws RepositoryException if an error occurs
+     * @throws RepositoryException
+     *             if an error occurs
      */
-    public QueryResult execute(long offset, long limit) throws RepositoryException {
-        if (log.isDebugEnabled()) {
-            log.debug("Executing query: \n" + root.dump());
-        }
+    public QueryResult execute(long offset, long limit)
+	    throws RepositoryException {
+	if (log.isDebugEnabled()) {
+	    log.debug("Executing query: \n" + root.dump());
+	}
 
-        // build lucene query
-        Query query = LuceneQueryBuilder.createQuery(root, session,
-                index.getContext().getItemStateManager(),
-                index.getNamespaceMappings(), index.getTextAnalyzer(),
-                propReg, index.getSynonymProvider(),
-                index.getIndexFormatVersion());
+	// build lucene query
+	Query query = LuceneQueryBuilder.createQuery(root, session, index
+		.getContext().getItemStateManager(), index
+		.getNamespaceMappings(), index.getTextAnalyzer(), propReg,
+		index.getSynonymProvider(), index.getIndexFormatVersion(),
+		index.getContext().getVirtualTableResolver());
 
-        OrderQueryNode orderNode = root.getOrderNode();
+	OrderQueryNode orderNode = root.getOrderNode();
 
-        OrderQueryNode.OrderSpec[] orderSpecs;
-        if (orderNode != null) {
-            orderSpecs = orderNode.getOrderSpecs();
-        } else {
-            orderSpecs = new OrderQueryNode.OrderSpec[0];
-        }
-        QPath[] orderProperties = new QPath[orderSpecs.length];
-        boolean[] ascSpecs = new boolean[orderSpecs.length];
-        for (int i = 0; i < orderSpecs.length; i++) {
-            orderProperties[i] = orderSpecs[i].getPropertyPath();
-            ascSpecs[i] = orderSpecs[i].isAscending();
-        }
+	OrderQueryNode.OrderSpec[] orderSpecs;
+	if (orderNode != null) {
+	    orderSpecs = orderNode.getOrderSpecs();
+	} else {
+	    orderSpecs = new OrderQueryNode.OrderSpec[0];
+	}
+	QPath[] orderProperties = new QPath[orderSpecs.length];
+	boolean[] ascSpecs = new boolean[orderSpecs.length];
+	for (int i = 0; i < orderSpecs.length; i++) {
+	    orderProperties[i] = orderSpecs[i].getPropertyPath();
+	    ascSpecs[i] = orderSpecs[i].isAscending();
+	}
 
-        return new SingleColumnQueryResult(index, itemMgr,
-                session, session.getAccessManager(),
-                this, query, new SpellSuggestion(index.getSpellChecker(), root),
-                getSelectProperties(), orderProperties, ascSpecs,
-                getRespectDocumentOrder(), offset, limit);
+	return new SingleColumnQueryResult(index, itemMgr, session, session
+		.getAccessManager(), this, query, new SpellSuggestion(index
+		.getSpellChecker(), root), getSelectProperties(),
+		orderProperties, ascSpecs, getRespectDocumentOrder(), offset,
+		limit);
     }
 
     /**
      * Returns the select properties for this query.
-     *
+     * 
      * @return array of select property names.
-     * @throws RepositoryException if an error occurs.
+     * @throws RepositoryException
+     *             if an error occurs.
      */
     protected InternalQName[] getSelectProperties() throws RepositoryException {
-        // get select properties
-        List selectProps = new ArrayList();
-        selectProps.addAll(Arrays.asList(root.getSelectProperties()));
-        if (selectProps.size() == 0) {
-            // use node type constraint
-            LocationStepQueryNode[] steps = root.getLocationNode().getPathSteps();
-            final InternalQName[] ntName = new InternalQName[1];
-            steps[steps.length - 1].acceptOperands(new DefaultQueryNodeVisitor() {
+	// get select properties
+	List selectProps = new ArrayList();
+	selectProps.addAll(Arrays.asList(root.getSelectProperties()));
+	if (selectProps.size() == 0) {
+	    // use node type constraint
+	    LocationStepQueryNode[] steps = root.getLocationNode()
+		    .getPathSteps();
+	    final InternalQName[] ntName = new InternalQName[1];
+	    steps[steps.length - 1].acceptOperands(
+		    new DefaultQueryNodeVisitor() {
 
-                public Object visit(AndQueryNode node, Object data) throws RepositoryException {
-                    return node.acceptOperands(this, data);
-                }
+			public Object visit(AndQueryNode node, Object data)
+				throws RepositoryException {
+			    return node.acceptOperands(this, data);
+			}
 
-                public Object visit(NodeTypeQueryNode node, Object data) {
-                    ntName[0] = node.getValue();
-                    return data;
-                }
-            }, null);
-            if (ntName[0] == null) {
-                ntName[0] = Constants.NT_BASE;
-            }
-            NodeTypeData nt = session.getWorkspace().getNodeTypesHolder().findNodeType(ntName[0]);
-            PropertyDefinitionData[] propDefs = nt.getDeclaredPropertyDefinitions();
-            
-            for (int i = 0; i < propDefs.length; i++) {
-               PropertyDefinitionData propDef = propDefs[i];
-               if (!propDef.isResidualSet() && !propDef.isMultiple())
-               {
-                  selectProps.add(propDef.getName());
-               }
-            }
-        }
+			public Object visit(NodeTypeQueryNode node, Object data) {
+			    ntName[0] = node.getValue();
+			    return data;
+			}
+		    }, null);
+	    if (ntName[0] == null) {
+		ntName[0] = Constants.NT_BASE;
+	    }
+	    NodeTypeData nt = session.getWorkspace().getNodeTypesHolder()
+		    .findNodeType(ntName[0]);
+	    PropertyDefinitionData[] propDefs = nt
+		    .getDeclaredPropertyDefinitions();
 
-        // add jcr:path and jcr:score if not selected already
-        if (!selectProps.contains(Constants.JCR_PATH))
-        {
-           selectProps.add(Constants.JCR_PATH);
-        }
-        if (!selectProps.contains(Constants.JCR_SCORE))
-        {
-           selectProps.add(Constants.JCR_SCORE);
-        }
+	    for (int i = 0; i < propDefs.length; i++) {
+		PropertyDefinitionData propDef = propDefs[i];
+		if (!propDef.isResidualSet() && !propDef.isMultiple()) {
+		    selectProps.add(propDef.getName());
+		}
+	    }
+	}
 
-        return (InternalQName[])selectProps.toArray(new InternalQName[selectProps.size()]);
+	// add jcr:path and jcr:score if not selected already
+	if (!selectProps.contains(Constants.JCR_PATH)) {
+	    selectProps.add(Constants.JCR_PATH);
+	}
+	if (!selectProps.contains(Constants.JCR_SCORE)) {
+	    selectProps.add(Constants.JCR_SCORE);
+	}
+
+	return (InternalQName[]) selectProps
+		.toArray(new InternalQName[selectProps.size()]);
     }
 
     /**
      * Returns <code>true</code> if this query node needs items under
      * /jcr:system to be queried.
-     *
+     * 
      * @return <code>true</code> if this query node needs content under
      *         /jcr:system to be queried; <code>false</code> otherwise.
      */
     public boolean needsSystemTree() {
-        return this.root.needsSystemTree();
+	return this.root.needsSystemTree();
     }
 
 }

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/SearchIndex.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -87,24 +87,6 @@
  */
 public class SearchIndex extends AbstractQueryHandler {
 
-    // public static final List VALID_SYSTEM_INDEX_NODE_TYPE_NAMES
-    // = Collections.unmodifiableList(Arrays.asList(new Name[]{
-    // NameConstants.NT_CHILDNODEDEFINITION,
-    // NameConstants.NT_FROZENNODE,
-    // NameConstants.NT_NODETYPE,
-    // NameConstants.NT_PROPERTYDEFINITION,
-    // NameConstants.NT_VERSION,
-    // NameConstants.NT_VERSIONEDCHILD,
-    // NameConstants.NT_VERSIONHISTORY,
-    // NameConstants.NT_VERSIONLABELS,
-    // NameConstants.REP_NODETYPES,
-    // NameConstants.REP_SYSTEM,
-    // NameConstants.REP_VERSIONSTORAGE,
-    // // Supertypes
-    // NameConstants.NT_BASE,
-    // NameConstants.MIX_REFERENCEABLE
-    // }));
-
     private static final DefaultQueryNodeFactory DEFAULT_QUERY_NODE_FACTORY = new DefaultQueryNodeFactory();
 
     /** The logger instance for this class */
@@ -162,32 +144,10 @@
      */
     public static final int DEFAULT_TERM_INFOS_INDEX_DIVISOR = 1;
 
-    // /**
-    // * The path factory.
-    // */
-    // protected static final PathFactory PATH_FACTORY =
-    // PathFactoryImpl.getInstance();
-    //
-    // /**
-    // * The path of the root node.
-    // */
-    // private static final Path ROOT_PATH;
-    //
-    // /**
-    // * The path <code>/jcr:system</code>.
-    // */
-    // private static final Path JCR_SYSTEM_PATH;
-    //
-    // static {
-    // ROOT_PATH = PATH_FACTORY.create(NameConstants.ROOT);
-    // try {
-    // JCR_SYSTEM_PATH = PATH_FACTORY.create(ROOT_PATH,
-    // NameConstants.JCR_SYSTEM, false);
-    // } catch (RepositoryException e) {
-    // // should never happen, path is always valid
-    // throw new InternalError(e.getMessage());
-    // }
-    // }
+    /**
+     * Default name of the error log file
+     */
+    private static final String ERROR_LOG = "error.log";
 
     /**
      * The actual index
@@ -199,19 +159,6 @@
      */
     private JcrStandartAnalyzer analyzer;
 
-    // /**
-    // * List of text extractor and text filter class names. The configured
-    // * classes will be instantiated and used to extract text content from
-    // * binary properties.
-    // */
-    // private String textFilterClasses =
-    // DefaultTextExtractor.class.getName();
-    //
-    // /**
-    // * Text extractor for extracting text content of binary properties.
-    // */
-    // private TextExtractor extractor;
-
     /**
      * The namespace mappings used internally.
      */
@@ -380,8 +327,6 @@
      */
     private SynonymProvider synProvider;
 
-    // private File indexDirectory;
-
     /**
      * The configuration path for the synonym provider.
      */
@@ -451,15 +396,14 @@
      */
     private boolean closed = false;
 
-    // private QueryHandlerContext context;
-
     /**
      * Text extractor for extracting text content of binary properties.
      */
     private DocumentReaderService extractor;
 
-    // private final QueryHandlerEntryWrapper queryHandlerConfig;
+    public static final int DEFAULT_ERRORLOG_FILE_SIZE = 50; // Kb
 
+    private int errorLogfileSize = DEFAULT_ERRORLOG_FILE_SIZE;
     /**
      * The ErrorLog of this <code>MultiIndex</code>. All changes that must be in
      * index but interrupted by IOException are here.
@@ -601,9 +545,30 @@
 		    + "storage for optimal performance.", new Integer(
 		    getIndexFormatVersion().getVersion()));
 	}
+
+	File file = new File(indexDirectory, ERROR_LOG);
+	errorLog = new ErrorLog(file, errorLogfileSize);
+	// reprocess any notfinished notifies;
+	recoverErrorLog(errorLog);
+
     }
 
     /**
+     * @return the errorLogfileSize
+     */
+    public int getErrorLogfileSize() {
+	return errorLogfileSize;
+    }
+
+    /**
+     * @param errorLogfileSize
+     *            the errorLogfileSize to set
+     */
+    public void setErrorLogfileSize(int errorLogfileSize) {
+	this.errorLogfileSize = errorLogfileSize;
+    }
+
+    /**
      * Adds the <code>node</code> to the search index.
      * 
      * @param node
@@ -1308,34 +1273,39 @@
      * @return the indexing configuration or <code>null</code> if there is none.
      */
     protected Element getIndexingConfigurationDOM() {
-	if (indexingConfiguration != null) {
-	    return indexingConfiguration;
+	if (indexingConfiguration == null) {
+	    if (indexingConfigPath != null) {
+
+		// File config = new File(indexingConfigPath);
+
+		InputStream is = SearchIndex.class
+			.getResourceAsStream(indexingConfigPath);
+		if (is == null) {
+		    try {
+			is = cfm.getInputStream(indexingConfigPath);
+		    } catch (Exception e1) {
+			log.warn("Unable to load configuration "
+				+ indexingConfigPath);
+		    }
+		}
+
+		try {
+		    DocumentBuilderFactory factory = DocumentBuilderFactory
+			    .newInstance();
+		    DocumentBuilder builder = factory.newDocumentBuilder();
+		    builder
+			    .setEntityResolver(new IndexingConfigurationEntityResolver());
+		    indexingConfiguration = builder.parse(is)
+			    .getDocumentElement();
+		} catch (ParserConfigurationException e) {
+		    log.warn("Unable to create XML parser", e);
+		} catch (IOException e) {
+		    log.warn("Exception parsing " + indexingConfigPath, e);
+		} catch (SAXException e) {
+		    log.warn("Exception parsing " + indexingConfigPath, e);
+		}
+	    }
 	}
-	if (indexingConfigPath == null) {
-	    return null;
-	}
-	File config = new File(indexingConfigPath);
-	if (!config.exists()) {
-	    log.warn("File does not exist: " + indexingConfigPath);
-	    return null;
-	} else if (!config.canRead()) {
-	    log.warn("Cannot read file: " + indexingConfigPath);
-	    return null;
-	}
-	try {
-	    DocumentBuilderFactory factory = DocumentBuilderFactory
-		    .newInstance();
-	    DocumentBuilder builder = factory.newDocumentBuilder();
-	    builder
-		    .setEntityResolver(new IndexingConfigurationEntityResolver());
-	    indexingConfiguration = builder.parse(config).getDocumentElement();
-	} catch (ParserConfigurationException e) {
-	    log.warn("Unable to create XML parser", e);
-	} catch (IOException e) {
-	    log.warn("Exception parsing " + indexingConfigPath, e);
-	} catch (SAXException e) {
-	    log.warn("Exception parsing " + indexingConfigPath, e);
-	}
 	return indexingConfiguration;
     }
 
@@ -2384,6 +2354,72 @@
 	errorLog.writeChanges(removed, added);
     }
 
+    private void recoverErrorLog(ErrorLog errlog) throws IOException,
+	    RepositoryException {
+	final Set<String> rem = new HashSet<String>();
+	final Set<String> add = new HashSet<String>();
+
+	errlog.readChanges(rem, add);
+
+	// check is any notifies in log
+	if (rem.isEmpty() && add.isEmpty()) {
+	    // there is no sense to continue
+	    return;
+	}
+
+	Iterator<String> removedStates = rem.iterator();
+
+	// make a new iterator;
+	Iterator<NodeData> addedStates = new Iterator<NodeData>() {
+	    private final Iterator<String> iter = add.iterator();
+
+	    public boolean hasNext() {
+		return iter.hasNext();
+	    }
+
+	    public NodeData next() {
+		String id;
+		// we have to iterrate through items till will meet ones
+		// existing in
+		// workspace
+		while (iter.hasNext()) {
+		    id = iter.next();
+
+		    try {
+			ItemData item = getContext().getItemStateManager()
+				.getItemData(id);
+			if (item != null) {
+			    if (item.isNode()) {
+				return (NodeData) item; // return node here
+			    } else
+				log
+					.warn("Node expected but property found with id "
+						+ id
+						+ ". Skipping "
+						+ item.getQPath().getAsString());
+			} else {
+			    log.warn("Unable to recovery node index " + id
+				    + ". Node not found.");
+			}
+		    } catch (RepositoryException e) {
+			log.error("ErrorLog recovery error. Item id " + id
+				+ ". " + e, e);
+		    }
+		}
+
+		return null;
+	    }
+
+	    public void remove() {
+		throw new UnsupportedOperationException();
+	    }
+	};
+
+	updateNodes(removedStates, addedStates);
+
+	errlog.clear();
+    }
+
     /**
      * @see org.exoplatform.services.jcr.impl.core.query.QueryHandler#executeQuery(org.apache.lucene.search.Query,
      *      boolean, org.exoplatform.services.jcr.datamodel.InternalQName[],
@@ -2398,4 +2434,5 @@
 
 	return new LuceneQueryHits(reader, searcher, query);
     }
+
 }

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/VirtualTableResolver.java
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/VirtualTableResolver.java	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/VirtualTableResolver.java	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 eXo Platform SAS.
+ *
+ * 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 org.exoplatform.services.jcr.impl.core.query.lucene;
+
+import org.exoplatform.services.jcr.datamodel.InternalQName;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.query.InvalidQueryException;
+
+/**
+ * @author <a href="mailto:Sergey.Kabashnyuk at gmail.com">Sergey Kabashnyuk</a>
+ * @version $Id: exo-jboss-codetemplates.xml 34027 2009-07-15 23:26:43Z
+ *          aheritier $
+ */
+public interface VirtualTableResolver<Q>
+{
+   /**
+    * Construct <Q>query for given table.
+    * 
+    * @param tableName - name of the virtual table.
+    * @param includeInheritedTables - include inherited tables to the result.
+    * @return query.
+    */
+   Q resolve(InternalQName tableName, boolean includeInheritedTables) throws InvalidQueryException, RepositoryException;
+
+}


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/VirtualTableResolver.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.0.dtd
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.0.dtd	2009-10-02 15:39:44 UTC (rev 197)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.0.dtd	2009-10-02 15:41:14 UTC (rev 198)
@@ -16,7 +16,7 @@
 -->
 <!--
     The configuration element configures the indexing behaviour of the lucene
-    backed query handler in Jackrabbit. It allows you to define indexing
+    backed query handler . It allows you to define indexing
     aggregates and configure which properties of a node are indexed.
     This element must contain all the namespace declarations that are used
     throughout this configuration.

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.1.dtd
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.1.dtd	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.1.dtd	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,84 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+    The configuration element configures the indexing behaviour of the lucene
+    backed query handler . It allows you to define indexing
+    aggregates and configure which properties of a node are indexed.
+    This element must contain all the namespace declarations that are used
+    throughout this configuration.
+-->
+<!ELEMENT configuration (aggregate*,index-rule*)>
+
+<!--
+    Each aggregate element defines an indexing aggregate based on the name of a
+    primary node type.
+-->
+<!ELEMENT aggregate (include*)>
+<!ATTLIST aggregate primaryType CDATA #REQUIRED>
+
+<!--
+    An include element contains a relative path pattern using either an exact
+    node name or *. Nodes that match the path pattern against the root of an
+    indexing aggregate are included in the aggregated node index. An include
+    element may optionally specify a primary node type name that needs to match
+    for the included node.
+-->
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include primaryType CDATA #IMPLIED>
+
+<!--
+    An index-rule element defines which properties of a node should be indexed.
+    When a node is indexed the list of index-rules is check for a matching
+    node type and whether the condition is true. If a match is found the
+    property is looked up.
+    The index-rule element also contains a boost value for the entire node
+    being indexed. A value higher than 1.0 will boost the score value for a node
+    that matched this index-rule.
+-->
+<!ELEMENT index-rule (property*)>
+<!ATTLIST index-rule nodeType CDATA #REQUIRED
+                     condition CDATA #IMPLIED
+                     boost CDATA "1.0">
+
+<!--
+    A property element defines the boost value for a matching property and a
+    flag that indicates whether the value of a string property should also be
+    included in the node scope fulltext index. Both boost and nodeScopeIndex
+    attributes only affect string properties and are ignored if the property
+    is not of type string. If isRegexp is set to true the name of the property
+    is interpreted as a regular expression to match properties on a node. Please
+    note that you may only use a regular expression for the local part of a
+    property name. The attribute useInExcerpt controls whether the contents
+    of the property is used to construct an excerpt. The default value for this
+    attribute is true.
+-->
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property boost CDATA "1.0"
+                   nodeScopeIndex CDATA "true"
+                   isRegexp CDATA "false"
+                   useInExcerpt CDATA "true">
+
+<!--
+    An analyzer element with property elements in it defines which analyzer is to
+    be used for indexing and parsing the full text of this property. If the analyzer
+    class can not be found, the default analyzer is used. The node scope is always
+    indexed with the default analyzer, so might return different results for search
+    queries in some rare cases.
+-->
+<!ELEMENT analyzers (analyzer*)>
+<!ELEMENT analyzer (property*)>
+<!ATTLIST analyzer class CDATA #REQUIRED>


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.1.dtd
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Added: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.2.dtd
===================================================================
--- jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.2.dtd	                        (rev 0)
+++ jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.2.dtd	2009-10-02 15:41:14 UTC (rev 198)
@@ -0,0 +1,93 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+    The configuration element configures the indexing behaviour of the lucene
+    backed query handler. It allows you to define indexing
+    aggregates and configure which properties of a node are indexed.
+    This element must contain all the namespace declarations that are used
+    throughout this configuration.
+-->
+<!ELEMENT configuration (aggregate*,index-rule*)>
+
+<!--
+    Each aggregate element defines an indexing aggregate based on the name of a
+    primary node type.
+-->
+<!ELEMENT aggregate (include*,include-property)>
+<!ATTLIST aggregate primaryType CDATA #REQUIRED>
+
+<!--
+    An include element contains a relative path pattern using either an exact
+    node name or *. Nodes that match the path pattern against the root of an
+    indexing aggregate are included in the aggregated node index. An include
+    element may optionally specify a primary node type name that needs to match
+    for the included node.
+-->
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include primaryType CDATA #IMPLIED>
+
+<!--
+    An include-property element contains a relative path to a property. Properties
+    that match the path against the root of an indexing aggregate are included
+    in the aggregated node index. Aggregated properties may be used to speed
+    up sorting of query results when the order by clause references a property
+    with a relative path.
+-->
+<!ELEMENT include-property (#PCDATA)>
+
+<!--
+    An index-rule element defines which properties of a node should be indexed.
+    When a node is indexed the list of index-rules is check for a matching
+    node type and whether the condition is true. If a match is found the
+    property is looked up.
+    The index-rule element also contains a boost value for the entire node
+    being indexed. A value higher than 1.0 will boost the score value for a node
+    that matched this index-rule.
+-->
+<!ELEMENT index-rule (property*)>
+<!ATTLIST index-rule nodeType CDATA #REQUIRED
+                     condition CDATA #IMPLIED
+                     boost CDATA "1.0">
+
+<!--
+    A property element defines the boost value for a matching property and a
+    flag that indicates whether the value of a string property should also be
+    included in the node scope fulltext index. Both boost and nodeScopeIndex
+    attributes only affect string properties and are ignored if the property
+    is not of type string. If isRegexp is set to true the name of the property
+    is interpreted as a regular expression to match properties on a node. Please
+    note that you may only use a regular expression for the local part of a
+    property name. The attribute useInExcerpt controls whether the contents
+    of the property is used to construct an excerpt. The default value for this
+    attribute is true.
+-->
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property boost CDATA "1.0"
+                   nodeScopeIndex CDATA "true"
+                   isRegexp CDATA "false"
+                   useInExcerpt CDATA "true">
+
+<!--
+    An analyzer element with property elements in it defines which analyzer is to
+    be used for indexing and parsing the full text of this property. If the analyzer
+    class can not be found, the default analyzer is used. The node scope is always
+    indexed with the default analyzer, so might return different results for search
+    queries in some rare cases.
+-->
+<!ELEMENT analyzers (analyzer*)>
+<!ELEMENT analyzer (property*)>
+<!ATTLIST analyzer class CDATA #REQUIRED>


Property changes on: jcr/trunk/component/core/src/main/java/org/exoplatform/services/jcr/impl/core/query/lucene/indexing-configuration-1.2.dtd
___________________________________________________________________
Name: svn:mime-type
   + text/plain



More information about the exo-jcr-commits mailing list