You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2005/02/22 17:35:10 UTC

svn commit: r154873 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: ./ nodetype/ search/ search/lucene/

Author: mreutegg
Date: Tue Feb 22 08:35:06 2005
New Revision: 154873

URL: http://svn.apache.org/viewcvs?view=rev&rev=154873
Log:
Implement coercing of String literals into JCR PropertyTypes.

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java   (with props)
Modified:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/RepositoryImpl.java Tue Feb 22 08:35:06 2005
@@ -904,7 +904,7 @@
                     // no search index configured
                     return null;
                 }
-                searchMgr = new SearchManager(getSystemSession(), config.getSearchConfig());
+                searchMgr = new SearchManager(getSystemSession(), config.getSearchConfig(), ntReg);
             }
             return searchMgr;
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/SearchManager.java Tue Feb 22 08:35:06 2005
@@ -24,8 +24,10 @@
 import org.apache.jackrabbit.core.observation.SynchronousEventListener;
 import org.apache.jackrabbit.core.search.QueryHandler;
 import org.apache.jackrabbit.core.search.QueryImpl;
+import org.apache.jackrabbit.core.search.PropertyTypeRegistry;
 import org.apache.jackrabbit.core.state.ItemStateException;
 import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
 import org.apache.log4j.Logger;
 
 import javax.jcr.NamespaceException;
@@ -96,7 +98,7 @@
      */
     private final QueryHandler handler;
 
-    public SearchManager(SessionImpl session, SearchConfig config)
+    public SearchManager(SessionImpl session, SearchConfig config, NodeTypeRegistry ntReg)
             throws RepositoryException {
         this.session = session;
         this.hmgr = session.getHierarchyManager();
@@ -123,12 +125,14 @@
             nsReg.registerNamespace(NS_JCRFN_PREFIX, NS_JCRFN_URI);
         }
 
+        PropertyTypeRegistry propRegistry = new PropertyTypeRegistry(ntReg);
+        ntReg.addListener(propRegistry);
         // initialize query handler
         try {
             Class handlerClass = Class.forName(config.getHandlerClassName());
             handler = (QueryHandler) handlerClass.newInstance();
             NodeId rootId = (NodeId) session.hierMgr.resolvePath(Path.ROOT);
-            handler.init(fs, session.getItemStateManager(), rootId.getUUID());
+            handler.init(fs, session.getItemStateManager(), rootId.getUUID(), propRegistry);
         } catch (Exception e) {
             throw new RepositoryException(e.getMessage(), e);
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java Tue Feb 22 08:35:06 2005
@@ -391,7 +391,7 @@
      * @param listener the new listener to be informed on (un)registration
      *                 of node types
      */
-    void addListener(NodeTypeRegistryListener listener) {
+    public void addListener(NodeTypeRegistryListener listener) {
         if (!listeners.containsKey(listener)) {
             listeners.put(listener, listener);
         }
@@ -402,7 +402,7 @@
      *
      * @param listener an existing listener
      */
-    void removeListener(NodeTypeRegistryListener listener) {
+    public void removeListener(NodeTypeRegistryListener listener) {
         listeners.remove(listener);
     }
 
@@ -822,9 +822,12 @@
     }
 
     /**
-     * @return
+     * Returns the names of all registered node types. That includes primary
+     * and mixin node types.
+     *
+     * @return the names of all registered node types.
      */
-    synchronized QName[] getRegisteredNodeTypes() {
+    public synchronized QName[] getRegisteredNodeTypes() {
         return (QName[]) registeredNTDefs.keySet().toArray(new QName[registeredNTDefs.size()]);
     }
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/AbstractQueryHandler.java Tue Feb 22 08:35:06 2005
@@ -37,6 +37,11 @@
     private ItemStateManager stateProvider;
 
     /**
+     * PropertyType registry to look up the type of a property with a given name.
+     */ 
+    private PropertyTypeRegistry propRegistry;
+
+    /**
      * The UUID of the root node.
      */
     private String rootUUID;
@@ -49,12 +54,17 @@
      *                      <code>QueryHandler</code> may use to store its index.
      * @param stateProvider provides persistent item states.
      * @param rootUUID the uuid of the root node.
+     * @param registry the property type registry.
      */
-    public final void init(FileSystem fs, ItemStateManager stateProvider, String rootUUID)
+    public final void init(FileSystem fs, 
+                           ItemStateManager stateProvider, 
+                           String rootUUID,
+                           PropertyTypeRegistry registry)
             throws IOException {
         this.fs = fs;
         this.stateProvider = stateProvider;
         this.rootUUID = rootUUID;
+        this.propRegistry = registry;
         doInit();
     }
 
@@ -92,5 +102,13 @@
      */
     protected String getRootUUID() {
         return rootUUID;
+    }
+
+    /**
+     * Returns the PropertyTypeRegistry for this repository.
+     * @return the PropertyTypeRegistry for this repository.
+     */
+    protected PropertyTypeRegistry getPropertyTypeRegistry() {
+        return propRegistry;
     }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java?view=auto&rev=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java Tue Feb 22 08:35:06 2005
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.search;
+
+import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.Constants;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistryListener;
+import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
+import org.apache.jackrabbit.core.nodetype.PropDef;
+import org.apache.log4j.Logger;
+
+import javax.jcr.PropertyType;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The <code>PropertyTypeRegistry</code> keeps track of registered node type
+ * definitions and its property types. It provides a fast type lookup for a
+ * given property name.
+ */
+public class PropertyTypeRegistry implements NodeTypeRegistryListener {
+
+    /** The logger instance for this class */
+    private static final Logger log = Logger.getLogger(PropertyTypeRegistry.class);
+
+    /** '*' denoting residual child item definition */
+    protected static final QName ANY_NAME = new QName(Constants.NS_DEFAULT_URI, "*");
+
+    /**
+     * Empty <code>TypeMapping</code> array as return value if no type is
+     * found
+     */
+    private static final TypeMapping[] EMPTY = new TypeMapping[0];
+
+    /** The NodeTypeRegistry */
+    private final NodeTypeRegistry registry;
+
+    /** Property QName to TypeMapping[] mapping */
+    private final Map typeMapping = new HashMap();
+
+    /**
+     * Creates a new <code>PropertyTypeRegistry</code> instance. This instance
+     * is *not* registered as listener to the NodeTypeRegistry in the constructor!
+     * @param reg the <code>NodeTypeRegistry</code> where to read the property
+     * type information.
+     */
+    public PropertyTypeRegistry(NodeTypeRegistry reg) {
+        this.registry = reg;
+        fillCache();
+    }
+
+    /**
+     * Returns an array of type mappings for a given property name
+     * <code>propName</code>. If <code>propName</code> is not defined as a property
+     * in any registered node type an empty array is returned.
+     * @param propName the name of the property.
+     * @return an array of <code>TypeMapping</code> instances.
+     */
+    public TypeMapping[] getPropertyTypes(QName propName) {
+        synchronized (typeMapping) {
+            TypeMapping[] types = (TypeMapping[]) typeMapping.get(propName);
+            return (types != null) ? types : EMPTY;
+        }
+    }
+
+    public void nodeTypeRegistered(QName ntName) {
+        try {
+            NodeTypeDef def = registry.getNodeTypeDef(ntName);
+            PropDef[] propDefs = def.getPropertyDefs();
+            synchronized (typeMapping) {
+                for (int i = 0; i < propDefs.length; i++) {
+                    QName name = propDefs[i].getName();
+                    int type = propDefs[i].getRequiredType();
+                    if (!ANY_NAME.equals(name) && type != PropertyType.UNDEFINED) {
+                        // only remember defined property types
+                        TypeMapping[] types = (TypeMapping[]) typeMapping.get(name);
+                        if (types == null) {
+                            types = new TypeMapping[1];
+                        } else {
+                            TypeMapping[] tmp = new TypeMapping[types.length + 1];
+                            System.arraycopy(types, 0, tmp, 0, types.length);
+                            types = tmp;
+                        }
+                        types[types.length - 1] = new TypeMapping(type, ntName);
+                        typeMapping.put(name, types);
+                    }
+                }
+            }
+        } catch (NoSuchNodeTypeException e) {
+            log.error("Unable to get newly registered node type definition for name: " + ntName);
+        }
+    }
+
+    public void nodeTypeReRegistered(QName ntName) {
+        nodeTypeUnregistered(ntName);
+        nodeTypeRegistered(ntName);
+    }
+
+    public void nodeTypeUnregistered(QName ntName) {
+        // remove all TypeMapping instances refering to this ntName
+        synchronized (typeMapping) {
+            Map modified = new HashMap();
+            for (Iterator it = typeMapping.keySet().iterator(); it.hasNext();) {
+                QName propName = (QName) it.next();
+                TypeMapping[] mapping = (TypeMapping[]) typeMapping.get(propName);
+                List remove = null;
+                for (int i = 0; i < mapping.length; i++) {
+                    if (mapping[i].ntName.equals(ntName)) {
+                        if (remove == null) {
+                            // not yet created
+                            remove = new ArrayList(mapping.length);
+                        }
+                        remove.add(mapping[i]);
+                    }
+                }
+                if (remove != null) {
+                    it.remove();
+                    if (mapping.length == remove.size()) {
+                        // all removed -> done
+                    } else {
+                        // only some removed
+                        List remaining = new ArrayList(Arrays.asList(mapping));
+                        remaining.removeAll(remove);
+                        modified.put(propName, remaining.toArray(new TypeMapping[remaining.size()]));
+                    }
+                }
+            }
+            // finally re-add the modified mappings
+            typeMapping.putAll(modified);
+        }
+    }
+
+    /**
+     * Initially fills the cache of this registry with property type definitions
+     * from the {@link org.apache.jackrabbit.core.nodetype.NodeTypeRegistry}.
+     */
+    private void fillCache() {
+        QName[] ntNames = registry.getRegisteredNodeTypes();
+        for (int i = 0; i < ntNames.length; i++) {
+            nodeTypeRegistered(ntNames[i]);
+        }
+    }
+
+    public static class TypeMapping {
+
+        /** The property type as an integer */
+        public final int type;
+
+        /** The QName of the node type where this type mapping originated */
+        final QName ntName;
+
+        private TypeMapping(int type, QName ntName) {
+            this.type = type;
+            this.ntName = ntName;
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/PropertyTypeRegistry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryHandler.java Tue Feb 22 08:35:06 2005
@@ -22,10 +22,8 @@
 import org.apache.jackrabbit.core.ItemManager;
 import org.apache.jackrabbit.core.fs.FileSystem;
 
-import javax.jcr.query.Query;
 import javax.jcr.query.InvalidQueryException;
 import javax.jcr.RepositoryException;
-import javax.jcr.Node;
 import java.io.IOException;
 
 /**
@@ -44,11 +42,13 @@
      *  <code>QueryHandler</code> may use to store its index.
      * @param stateProvider provides persistent item states.
      * @param rootUUID the UUID of the root node.
+     * @param registry the property type registry.
      * @throws IOException if an error occurs during initialization.
      */
     public void init(FileSystem fs,
                      ItemStateManager stateProvider,
-                     String rootUUID) throws IOException;
+                     String rootUUID,
+                     PropertyTypeRegistry registry) throws IOException;
 
     /**
      * Adds a <code>Node</code> to the search index.

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java Tue Feb 22 08:35:06 2005
@@ -29,6 +29,8 @@
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
+import javax.jcr.PropertyType;
+import javax.jcr.util.ISO8601;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.nodetype.NodeTypeIterator;
 import javax.jcr.nodetype.NodeTypeManager;
@@ -37,6 +39,7 @@
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Calendar;
 
 /**
  * Implements a query builder that takes an abstract query tree and creates
@@ -75,6 +78,11 @@
      * The analyzer instance to use for contains function query parsing
      */
     private Analyzer analyzer;
+    
+    /**
+     * The property type registry.
+     */ 
+    private PropertyTypeRegistry propRegistry;
 
     /**
      * Exceptions thrown during tree translation
@@ -88,15 +96,18 @@
      * @param session    of the user executing this query.
      * @param nsMappings namespace resolver for internal prefixes.
      * @param analyzer   for parsing the query statement of the contains function.
+     * @param propReg    the property type registry.
      */
     private LuceneQueryBuilder(QueryRootNode root,
                                SessionImpl session,
                                NamespaceMappings nsMappings,
-                               Analyzer analyzer) {
+                               Analyzer analyzer,
+                               PropertyTypeRegistry propReg) {
         this.root = root;
         this.session = session;
         this.nsMappings = nsMappings;
         this.analyzer = analyzer;
+        this.propRegistry = propReg;
     }
 
     /**
@@ -107,17 +118,19 @@
      * @param session    of the user executing the query.
      * @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.
      * @return the lucene query tree.
      * @throws RepositoryException if an error occurs during the translation.
      */
     public static Query createQuery(QueryRootNode root,
                                     SessionImpl session,
                                     NamespaceMappings nsMappings,
-                                    Analyzer analyzer)
+                                    Analyzer analyzer,
+                                    PropertyTypeRegistry propReg)
             throws RepositoryException {
 
         LuceneQueryBuilder builder = new LuceneQueryBuilder(root,
-                session, nsMappings, analyzer);
+                session, nsMappings, analyzer, propReg);
 
         Query q = builder.createLuceneQuery();
         if (builder.exceptions.size() > 0) {
@@ -396,22 +409,28 @@
 
     public Object visit(RelationQueryNode node, Object data) {
         Query query;
-        String stringValue = null;
+        String stringValues[] = new String[1];
         switch (node.getValueType()) {
             case 0:
                 // not set: either IS NULL or IS NOT NULL
                 break;
             case QueryConstants.TYPE_DATE:
-                stringValue = DateField.dateToString(node.getDateValue());
+                stringValues[0] = DateField.dateToString(node.getDateValue());
                 break;
             case QueryConstants.TYPE_DOUBLE:
-                stringValue = DoubleField.doubleToString(node.getDoubleValue());
+                stringValues[0] = DoubleField.doubleToString(node.getDoubleValue());
                 break;
             case QueryConstants.TYPE_LONG:
-                stringValue = LongField.longToString(node.getLongValue());
+                stringValues[0] = LongField.longToString(node.getLongValue());
                 break;
             case QueryConstants.TYPE_STRING:
-                stringValue = node.getStringValue();
+                if (node.getOperation() == QueryConstants.OPERATION_LIKE
+                        || node.getOperation() == QueryConstants.OPERATION_NULL
+                        || node.getOperation() == QueryConstants.OPERATION_NOT_NULL) {
+                    stringValues[0] = node.getStringValue();
+                } else {
+                    stringValues = getStringValues(node.getProperty(), node.getStringValue());
+                }
                 break;
             default:
                 throw new IllegalArgumentException("Unknown relation type: "
@@ -439,38 +458,84 @@
 
         switch (node.getOperation()) {
             case QueryConstants.OPERATION_EQ_VALUE:      // =
-                query = new TermQuery(new Term(field, stringValue));
+                if (stringValues.length == 1) {
+                    query = new TermQuery(new Term(field, stringValues[0]));
+                } else {
+                    BooleanQuery or = new BooleanQuery();
+                    for (int i = 0; i < stringValues.length; i++) {
+                        or.add(new TermQuery(new Term(field, stringValues[i])), false, false);
+                    }
+                    query = or;
+                }
                 break;
             case QueryConstants.OPERATION_EQ_GENERAL:    // =
                 // search in single and multi valued properties
                 BooleanQuery or = new BooleanQuery();
-                or.add(new TermQuery(new Term(field, stringValue)), false, false);
-                or.add(new TermQuery(new Term(mvpField, stringValue)), false, false);
+                for (int i = 0; i < stringValues.length; i++) {
+                    or.add(new TermQuery(new Term(field, stringValues[i])), false, false);
+                    or.add(new TermQuery(new Term(mvpField, stringValues[i])), false, false);
+                }
                 query = or;
                 break;
             case QueryConstants.OPERATION_GE_VALUE:      // >=
-                query = new RangeQuery(new Term(field, stringValue), null, true);
+                if (stringValues.length == 1) {
+                    query = new RangeQuery(new Term(field, stringValues[0]), null, true);
+                } else {
+                    or = new BooleanQuery();
+                    for (int i = 0; i < stringValues.length; i++) {
+                        or.add(new RangeQuery(new Term(field, stringValues[i]), null, true), false, false);
+                    }
+                    query = or;
+                }
                 break;
             case QueryConstants.OPERATION_GT_VALUE:      // >
-                query = new RangeQuery(new Term(field, stringValue), null, false);
+                if (stringValues.length == 1) {
+                    query = new RangeQuery(new Term(field, stringValues[0]), null, false);
+                } else {
+                    or = new BooleanQuery();
+                    for (int i = 0; i < stringValues.length; i++) {
+                        or.add(new RangeQuery(new Term(field, stringValues[i]), null, false), false, false);
+                    }
+                    query = or;
+                }
                 break;
             case QueryConstants.OPERATION_LE_VALUE:      // <=
-                query = new RangeQuery(null, new Term(field, stringValue), true);
+                if (stringValues.length == 1) {
+                    query = new RangeQuery(null, new Term(field, stringValues[0]), true);
+                } else {
+                    or = new BooleanQuery();
+                    for (int i = 0; i < stringValues.length; i++) {
+                        or.add(new RangeQuery(null, new Term(field, stringValues[i]), true), false, false);
+                    }
+                    query = or;
+                }
                 break;
             case QueryConstants.OPERATION_LIKE:          // LIKE
-                if (stringValue.equals("%")) {
+                // the like operation always has one string value.
+                // no coercing, see above
+                if (stringValues[0].equals("%")) {
                     query = new MatchAllQuery(field);
                 } else {
-                    query = new WildcardQuery(new Term(field, stringValue));
+                    query = new WildcardQuery(new Term(field, stringValues[0]));
                 }
                 break;
             case QueryConstants.OPERATION_LT_VALUE:      // <
-                query = new RangeQuery(null, new Term(field, stringValue), false);
+                if (stringValues.length == 1) {
+                    query = new RangeQuery(null, new Term(field, stringValues[0]), false);
+                } else {
+                    or = new BooleanQuery();
+                    for (int i = 0; i < stringValues.length; i++) {
+                        or.add(new RangeQuery(null, new Term(field, stringValues[i]), false), false, false);
+                    }
+                    query = or;
+                }
                 break;
             case QueryConstants.OPERATION_NE_VALUE:      // !=
                 BooleanQuery notQuery = new BooleanQuery();
                 notQuery.add(new MatchAllQuery(field), false, false);
-                notQuery.add(new TermQuery(new Term(field, stringValue)), false, true);
+                for (int i = 0; i < stringValues.length; i++) {
+                    notQuery.add(new TermQuery(new Term(field, stringValues[i])), false, true);
+                }
                 query = notQuery;
                 break;
             case QueryConstants.OPERATION_NE_GENERAL:    // !=
@@ -478,8 +543,10 @@
                 notQuery = new BooleanQuery();
                 notQuery.add(new MatchAllQuery(field), false, false);
                 notQuery.add(new MatchAllQuery(mvpField), false, false);
-                notQuery.add(new TermQuery(new Term(field, stringValue)), false, true);
-                notQuery.add(new TermQuery(new Term(mvpField, stringValue)), false, true);
+                for (int i = 0; i < stringValues.length; i++) {
+                    notQuery.add(new TermQuery(new Term(field, stringValues[i])), false, true);
+                    notQuery.add(new TermQuery(new Term(mvpField, stringValues[i])), false, true);
+                }
                 query = notQuery;
                 break;
             case QueryConstants.OPERATION_NULL:
@@ -500,5 +567,131 @@
 
     public Object visit(OrderQueryNode node, Object data) {
         return data;
+    }
+    
+    //---------------------------< internal >-----------------------------------
+    
+    /**
+     * 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(QName propertyName, String literal) {
+        PropertyTypeRegistry.TypeMapping[] types = propRegistry.getPropertyTypes(propertyName);
+        List values = new ArrayList();
+        for (int i = 0; i < types.length; i++) {
+            switch (types[i].type) {
+                case PropertyType.NAME:
+                    // try to translate name
+                    try {
+                        values.add(nsMappings.translatePropertyName(literal, session.getNamespaceResolver()));
+                        log.debug("Coerced " + literal + " into NAME.");
+                    } catch (IllegalNameException e) {
+                        log.warn("Unable to coerce '" + literal + "' into a NAME: " + e.toString());
+                    } catch (UnknownPrefixException e) {
+                        log.warn("Unable to coerce '" + literal + "' into a NAME: " + e.toString());
+                    }
+                    break;
+                case PropertyType.PATH:
+                    // try to translate path
+                    try {
+                        Path p = Path.create(literal, session.getNamespaceResolver(), false);
+                        values.add(p.toJCRPath(nsMappings));
+                        log.debug("Coerced " + literal + " into PATH.");
+                    } catch (MalformedPathException e) {
+                        log.warn("Unable to coerce '" + literal + "' into a PATH: " + e.toString());
+                    } catch (NoPrefixDeclaredException 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) {
+            // try to guess property type
+            if (literal.indexOf('/') > -1) {
+                // might be a path
+                try {
+                    values.add(Path.create(literal, session.getNamespaceResolver(), false).toJCRPath(nsMappings));
+                    log.debug("Coerced " + literal + " into PATH.");
+                } catch (Exception e) {
+                    // not a path
+                }
+            } else if (literal.indexOf(':') > -1) {
+                // might be a name
+                try {
+                    values.add(QName.fromJCRName(literal, session.getNamespaceResolver()));
+                    log.debug("Coerced " + literal + " into NAME.");
+                } catch (Exception e) {
+                    // not a name
+                    // 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()]);
     }
 }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java Tue Feb 22 08:35:06 2005
@@ -28,6 +28,7 @@
 import org.apache.jackrabbit.core.PropertyId;
 import org.apache.jackrabbit.core.InternalValue;
 import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.Path;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.PropertyType;
@@ -229,9 +230,15 @@
                         false));
                 break;
             case PropertyType.PATH:
-                String path = internalValue.toString();
+                Path path = (Path) internalValue;
+                String pathString = path.toString();
+                try {
+                    pathString = path.toJCRPath(mappings);
+                } catch (NoPrefixDeclaredException e) {
+                    // will never happen
+                }
                 doc.add(new Field(fieldName,
-                        path,
+                        pathString,
                         false,
                         true,
                         false));

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/QueryImpl.java Tue Feb 22 08:35:06 2005
@@ -65,11 +65,17 @@
     private final SearchIndex index;
 
     /**
+     * The property type registry for type lookup.
+     */
+    private final PropertyTypeRegistry propReg;
+
+    /**
      * 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.
      * @throws InvalidQueryException if the query statement is invalid according
@@ -78,11 +84,13 @@
     public QueryImpl(SessionImpl session,
                      ItemManager itemMgr,
                      SearchIndex index,
+                     PropertyTypeRegistry propReg,
                      String statement,
                      String language) throws InvalidQueryException {
         this.session = session;
         this.itemMgr = itemMgr;
         this.index = index;
+        this.propReg = propReg;
         // parse query according to language
         // build query tree
         this.root = QueryParser.parse(statement, language, session.getNamespaceResolver());
@@ -97,7 +105,7 @@
     public QueryResult execute() throws RepositoryException {
         // build lucene query
         Query query = LuceneQueryBuilder.createQuery(root,
-                session, index.getNamespaceMappings(), index.getAnalyzer());
+                session, index.getNamespaceMappings(), index.getAnalyzer(), propReg);
 
         OrderQueryNode orderNode = root.getOrderNode();
 

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java?view=diff&r1=154872&r2=154873
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/SearchIndex.java Tue Feb 22 08:35:06 2005
@@ -196,7 +196,7 @@
                                              String statement,
                                              String language)
             throws InvalidQueryException {
-        return new QueryImpl(session, itemMgr, this, statement, language);
+        return new QueryImpl(session, itemMgr, this, getPropertyTypeRegistry(), statement, language);
     }
 
     /**