svn commit: r628599 [1/2] - in /xml/xindice/trunk/java: src/org/apache/xindice/core/indexer/ src/org/apache/xindice/core/query/ tests/src/org/apache/xindice/core/indexer/ tests/src/org/apache/xindice/core/query/ tests/src/org/apache/xindice/integration...

[email protected]
Newsgroups gmane.text.xml.xindice.devel
Message-ID <[email protected]>
Author: natalia
Date: Sun Feb 17 18:33:55 2008
New Revision: 628599

URL: http://svn.apache.org/viewvc?rev=628599&view=rev
Log:
Changes to allow path in Index Pattern

Added:
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java   (with props)
Modified:
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/MemValueIndexer.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/NameIndexer.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/ValueIndexer.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/LuceneIndexerTest.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/NameIndexerTest.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/query/TextQueryResolverTest.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/DocumentHandler.java Sun Feb 17 18:33:55 2008
@@ -28,13 +28,15 @@
 import org.apache.xindice.xml.SymbolTable;
 import org.apache.xindice.xml.sax.CompressionHandler;
 import org.apache.xindice.xml.sax.SAXEventGenerator;
-
 import org.w3c.dom.Document;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
 import org.xml.sax.SAXException;
 
+import java.util.Iterator;
+import java.util.LinkedList;
+
 /**
  * DocumentHandler actually performs the work of adding and removing Indexer
  * entries by calling appropiate methods of IndexerEventHandler.
@@ -51,6 +53,7 @@
     private ObjectStack stack = new ObjectStack();
     private Indexer[] indexers;
     private IndexerEventHandler[] handlers;
+    private LinkedList path = new LinkedList();
 
     public Key key;
     public Document doc;
@@ -134,7 +137,7 @@
         }
     }
 
-    public void processEntry(IndexPattern pattern, String value, int pos, int len) {
+    private void processEntry(LazyIndexPattern pattern, String value, int pos, int len) {
         for (int i = 0; i < handlers.length; i++ ) {
             try {
                 switch (action) {
@@ -157,7 +160,7 @@
         }
     }
 
-    public void add(int n, IndexPattern ptrn, String value, Key key, int pos, int len) throws DBException {
+    private void add(int n, LazyIndexPattern ptrn, String value, Key key, int pos, int len) throws DBException {
         IndexPattern[] patterns = indexers[n].getPatterns();
         for (int i = 0; i < patterns.length; i++) {
             if (ptrn.getMatchLevel(patterns[i]) > 0) {
@@ -167,7 +170,7 @@
         }
     }
 
-    public void delete(int n, IndexPattern ptrn, String value, Key key, int pos, int len) throws DBException {
+    private void delete(int n, LazyIndexPattern ptrn, String value, Key key, int pos, int len) throws DBException {
         IndexPattern[] patterns = indexers[n].getPatterns();
         for (int i = 0; i < patterns.length; i++) {
             if (ptrn.getMatchLevel(patterns[i]) > 0) {
@@ -179,7 +182,7 @@
 
     public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
         try {
-// Modify the stack info to normalize the symbolID
+            // Modify the stack info to normalize the symbolID
             if (namespaceURI != null && namespaceURI.length() > 0) {
                 info.symbolID = symbols.getNormalizedSymbol(localName, namespaceURI, true);
             }
@@ -194,7 +197,7 @@
                     id = symbols.getSymbol(atts.getQName(i), true);
                 }
 
-                processEntry(new IndexPattern(symbols, info.symbolID, id), atts.getValue(i), info.pos, info.len);
+                processEntry(new LazyIndexPattern(id), atts.getValue(i), info.pos, info.len);
             }
         } catch (ReadOnlyException e) {
             throw new SAXException(e);
@@ -203,11 +206,12 @@
 
     public void endElement(String namespaceURI, String localName, String qName) {
         StringBuffer sb = info.sb;
-        processEntry(new IndexPattern(symbols, info.symbolID), sb.toString(), info.pos, info.len);
+        processEntry(new LazyIndexPattern(), sb.toString(), info.pos, info.len);
         info = (StackInfo) stack.pop();
         if (info != null) {
             info.sb.append(sb);
         }
+        path.removeLast();
     }
 
     public void characters(char ch[], int start, int length) {
@@ -219,6 +223,7 @@
             stack.push(info);
         }
         info = new StackInfo(symbolID);
+        path.add(new Short(symbolID));
     }
 
     public void dataLocation(int pos, int len) {
@@ -237,6 +242,63 @@
 
         public StackInfo(short symbolID) {
             this.symbolID = symbolID;
+        }
+    }
+
+    private class LazyIndexPattern {
+        private short attrID = IndexPattern.PATTERN_NONE;
+        private IndexPattern pattern;
+
+        public LazyIndexPattern() {
+        }
+
+        public LazyIndexPattern(short attrID) {
+            this.attrID = attrID;
+        }
+
+        public int getMatchLevel(IndexPattern p) {
+            if (pattern == null) {
+                if (p.isAbsolute() && p.getElementIDs().length != path.size()) {
+                    return 0;
+                }
+
+                if (p.getElementIDs().length > path.size()) {
+                    return 0;
+                }
+
+                short elemID = p.getElementID();
+                if (elemID != ((Short) path.getLast()).shortValue() && elemID != IndexPattern.PATTERN_WILDCARD) {
+                    return 0;
+                }
+
+                short attrID = p.getAttributeID();
+                if (this.attrID != attrID && (attrID != IndexPattern.PATTERN_WILDCARD || this.attrID == IndexPattern.PATTERN_NONE)) {
+                    return 0;
+                }
+
+                pattern = new IndexPattern(symbols, pathToArray(), this.attrID);
+            }
+
+            return pattern.getMatchLevel(p);
+        }
+
+        public short getElementID() {
+            return pattern.getElementID();
+        }
+
+        public short getAttributeID() {
+            return pattern.getAttributeID();
+        }
+
+        private short[] pathToArray() {
+            short[] array = new short[path.size()];
+
+            int j = 0;
+            for (Iterator i = path.iterator(); i.hasNext(); ) {
+                array[j++] = ((Short) i.next()).shortValue();
+            }
+
+            return array;
         }
     }
 }

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/IndexPattern.java Sun Feb 17 18:33:55 2008
@@ -20,15 +20,11 @@
 package org.apache.xindice.core.indexer;
 
 import org.apache.xindice.core.FaultCodes;
-import org.apache.xindice.core.filer.Streamable;
 import org.apache.xindice.util.ReadOnlyException;
 import org.apache.xindice.xml.NamespaceMap;
 import org.apache.xindice.xml.SymbolTable;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.StringTokenizer;
+import java.util.Arrays;
 
 /**
  * IndexPattern is the internal representation of a pattern for index
@@ -36,44 +32,91 @@
  *
  * @version $Revision$, $Date$
  */
-public final class IndexPattern implements Streamable {
+public final class IndexPattern {
 
     public static final int PATTERN_NONE     = -1;
     public static final int PATTERN_WILDCARD = -2;
-    public static final int PATTERN_NAME     = -3;
 
     public static final int SCORE_NONE     = 0;
     public static final int SCORE_WILDCARD = 1;
-    public static final int SCORE_NAME     = 2;
     public static final int SCORE_NATURAL  = 3;
 
 
     private SymbolTable symbols;
-    private String elemName;
-    private short elemID = PATTERN_NONE;
+    private boolean absolute;
+    private String[] elemName;
+    private short elemID[];
     private String attrName;
     private short attrID = PATTERN_NONE;
 
 
+    /**
+     * Creates IndexPattern object from a string that represents a path in
+     * a document to the element/attribute being indexed.<br/>
+     * <br/>
+     * Pattern consistes of any number of element names separated by symbol
+     * '/', optionally following by symbol '@' and an attribute name. Pattern
+     * path can be either relative or absolute.<br/>
+     * <br/>
+     * Any one element name or attribute name can be replaced with wildcard
+     * '*'.<br/>
+     * <br/>
+     * Pattern examples:<code><ul>
+     * <li>/elem1/elem2</li>
+     * <li>/elem1/elem2@attr</li>
+     * <li>elem1/elem2@attr</li>
+     * <li>&#42;/elem2@*</li>
+     * </ul></code>
+     * @param symbols Symbol table
+     * @param pattern String that represents the pattern
+     * @param nsMap Namespece map
+     * @throws IndexerException If collection is read-only and one or more
+     * elements of the pattern do not exist in the collection
+     */
     public IndexPattern(SymbolTable symbols, String pattern, NamespaceMap nsMap) throws IndexerException {
         this.symbols = symbols;
-        StringTokenizer st = new StringTokenizer(pattern.trim(), "@");
+
+        String ptrn = pattern.trim();
+        if (ptrn.charAt(0) == '/') {
+            absolute = true;
+            ptrn = ptrn.substring(1);
+        }
+
+        if (ptrn.length() == 0) {
+            throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
+        }
+
+        elemName = ptrn.split("/", -1);
+        elemID = new short[elemName.length];
 
         try {
-            elemName = st.nextToken();
-            if (elemName.equals("*")) {
-                elemID = PATTERN_WILDCARD;
-            } else {
-                elemID = symbols.getNormalizedSymbol(elemName, nsMap, true);
-            }
+            for (int i = 0; i < elemName.length; i++) {
+
+                if ("".equals(elemName[i])) {
+                    throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
+                }
+
+                int idx = elemName[i].indexOf('@');
+                if (idx >= 0) {
+
+                    if (i == elemName.length - 1) {
+                        attrName = elemName[i].substring(idx + 1);
+                        if (attrName.equals("*")) {
+                            attrID = PATTERN_WILDCARD;
+                        } else {
+                            attrID = symbols.getNormalizedSymbol(attrName, nsMap, true);
+                        }
+                    } else {
+                        throw new IndexerException(FaultCodes.IDX_CANNOT_CREATE, "Invalid pattern '" + pattern + "'");
+                    }
+
+                    elemName[i] = elemName[i].substring(0, idx);
+                }
 
-            if (st.hasMoreTokens()) {
-                attrName = st.nextToken();
-                if (attrName.equals("*")) {
-                    attrID = PATTERN_WILDCARD;
+                if (elemName[i].equals("*")) {
+                    elemID[i] = PATTERN_WILDCARD;
                 } else {
-                    attrID = elemID == PATTERN_WILDCARD ? PATTERN_NAME
-                            : symbols.getNormalizedSymbol(attrName, nsMap, true);
+                    elemID[i] = symbols.getNormalizedSymbol(elemName[i], nsMap, true);
                 }
             }
         } catch (ReadOnlyException e) {
@@ -82,82 +125,141 @@
         }
     }
 
-    public IndexPattern(SymbolTable symbols, short elemID) {
-        this.symbols = symbols;
-        this.elemID = elemID;
-        this.elemName = symbols.getName(elemID);
+    /**
+     * Creates new IndexPattern object with an absolute path that is represented
+     * by elemID arryay.
+     * @param symbols Symbol table
+     * @param elemID Array that holds symbols of elements of the path
+     */
+    public IndexPattern(SymbolTable symbols, short[] elemID) {
+        this(symbols, elemID, false);
     }
 
+    /**
+     * Creates new IndexPattern object with an absolute path that is represented
+     * by elemID arryay and attrID.
+     * @param symbols Symbol table
+     * @param elemID Array that holds symbols of elements of the path
+     * @param attrID Attribute symbol
+     */
+    public IndexPattern(SymbolTable symbols, short[] elemID, short attrID) {
+        this(symbols, elemID, attrID, true);
+    }
+
+    /**
+     * Creates new IndexPattern object with a relative path that is represented
+     * by single elemID and attrID.
+     * @param symbols Symbol table
+     * @param elemID Element symbol
+     * @param attrID Attribute symbol
+     */
     public IndexPattern(SymbolTable symbols, short elemID, short attrID) {
-        this.symbols = symbols;
-        this.elemID = elemID;
-		this.elemName = symbols.getName(elemID);
-        this.attrID = attrID;
-		this.attrName = symbols.getName(attrID);
+        this(symbols, new short[] { elemID }, attrID, false);
     }
 
-    public IndexPattern(SymbolTable symbols, short elemID, String attrName) {
+    /**
+     * Creates new IndexPattern object with a path that is represented by
+     * elemID arryay.
+     * @param symbols Symbol table
+     * @param elemID Array that holds symbols of elements of the path
+     * @param absolute True if path is absolute, false otherwise
+     */
+    public IndexPattern(SymbolTable symbols, short[] elemID, boolean absolute) {
+        this(symbols, elemID, (short) PATTERN_NONE, absolute);
+    }
+
+    /**
+     * Creates new IndexPattern object with a path that is represented by
+     * elemID arryay and attrID.
+     * @param symbols Symbol table
+     * @param elemID Array that holds symbols of elements of the path
+     * @param attrID Attribute symbol
+     * @param absolute True if path is absolute, false otherwise
+     */
+    public IndexPattern(SymbolTable symbols, short[] elemID, short attrID, boolean absolute) {
         this.symbols = symbols;
+
         this.elemID = elemID;
-        this.attrID = PATTERN_NAME;
-        this.attrName = attrName;
+        this.elemName = new String[elemID.length];
+        for (int i = 0; i < elemID.length; i++) {
+            this.elemName[i] = symbols.getName(elemID[i]);
+        }
+
+        this.attrID = attrID;
+        this.attrName = symbols.getName(attrID);
+
+        this.absolute = absolute;
     }
 
     /**
-     * getMatchLevel compares this IndexPattern to p.
-     *
-     * It returns the strength of
-     * the match betwen the two patterns from 0 to 15.  (0 being no match at
-     * all, 15 being perfect).  This method should be called by XPath and
-     * SAX patterns to be matched against Indexer patterns.
-     *
+     * Compares this IndexPattern to argument pattern p. The method checks
+     * if argument pattern can be used in place of this pattern.<br/>
+     * <br/>
+     * It returns the strength of the match between the two patterns that can
+     * be 0 or more, where 0 means the was no match at all. The maximum value
+     * of match depends on pattern length and therefore is different for
+     * different patterns.<br/>
+     * <br/>
+     * This method should be called by XPath and SAX patterns to be matched
+     * against Indexer patterns.
      * @param p The pattern to compare
      * @return The resulting IndexPattern strength
      */
     public int getMatchLevel(IndexPattern p) {
-        int result = 0;
+        // parameter pattern cannot match this pattern
+        if ((p.absolute && !absolute) || (p.elemID.length > elemID.length) ||
+            (p.absolute && absolute && p.elemID.length != elemID.length)) {
+            return 0;
+        }
 
-        switch (p.elemID) {
-            case PATTERN_WILDCARD:
-                result = (SCORE_WILDCARD << 2);
-                break;
-            case PATTERN_NAME:
-                if (p.elemName.equals(elemName)) {
-                    result = (SCORE_NAME << 2);
-                }
-                break;
-            default:
-                if (elemID == p.elemID) {
-                    result = (SCORE_NATURAL << 2);
-                }
+        int result;
+
+        if (attrID != PATTERN_NONE && p.attrID == PATTERN_WILDCARD) {
+            result = SCORE_WILDCARD;
+        } else if (attrID == p.attrID) {
+            result = SCORE_NATURAL;
+        } else {
+            return 0;
         }
 
-        if (result != 0) {
-            switch (p.attrID) {
-                case PATTERN_WILDCARD:
-                    return result + SCORE_WILDCARD;
-                case PATTERN_NAME:
-                    if (p.attrName.equals(attrName)) {
-                        return result + SCORE_NAME;
-                    }
-                    break;
-                default:
-                    if (attrID == p.attrID) {
-                        return result + SCORE_NATURAL;
-                    }
+        int i = elemID.length - 1;
+        int j = p.elemID.length - 1;
+        while (i >= 0 && j >=0) {
+            if (p.elemID[j] == PATTERN_WILDCARD) {
+                result += (SCORE_WILDCARD << 2);
+            } else if (elemID[i] == p.elemID[j]) {
+                result += (SCORE_NATURAL << 2);
+            } else {
+                result = 0;
+                break;
             }
+            i--;
+            j--;
         }
 
-        return 0;
+        return result;
+    }
+
+    public boolean isAbsolute() {
+        return absolute;
     }
 
     /**
-     * getElementID returns the Element Symbol ID for this pattern if
+     * getElementID returns the last Element Symbol ID for this pattern if
      * there is one, otherwise it returns a negative value.
      *
      * @return The Element Symbol ID
      */
     public short getElementID() {
+        return elemID.length > 0 ? elemID[elemID.length - 1] : PATTERN_NONE;
+    }
+
+    /**
+     * getElementID returns the arrays of Element Symbol ID for this pattern.
+     *
+     * @return The Element Symbol ID
+     */
+    public short[] getElementIDs() {
         return elemID;
     }
 
@@ -172,12 +274,11 @@
     }
 
     /**
-     * getElementName returns the Element Name for this pattern if
-     * there is one, otherwise it returns null.
+     * getElementNames returns the array of Element Name for this pattern.
      *
      * @return The Element Name
      */
-    public String getElementName() {
+    public String[] getElementNames() {
         return elemName;
     }
 
@@ -191,48 +292,16 @@
         return attrName;
     }
 
-    public void read(DataInput dis) throws IOException {
-        elemID = dis.readShort();
-        if (elemID == PATTERN_NAME) {
-            short len = dis.readShort();
-            byte[] name = new byte[len];
-            dis.readFully(name);
-            elemName = new String(name, "utf-8");
-        }
-        attrID = dis.readShort();
-        if (attrID == PATTERN_NAME) {
-            short len = dis.readShort();
-            byte[] name = new byte[len];
-            dis.readFully(name);
-            attrName = new String(name, "utf-8");
-        }
-    }
-
-    public void write(DataOutput dos) throws IOException {
-        dos.writeShort(elemID);
-        if (elemID == PATTERN_NAME) {
-            byte[] name = elemName.getBytes("utf-8");
-            dos.writeShort(name.length);
-            dos.write(name);
-        }
-        dos.writeShort(attrID);
-        if (attrID == PATTERN_NAME) {
-            byte[] name = attrName.getBytes("utf-8");
-            dos.writeShort(name.length);
-            dos.write(name);
-        }
-    }
-
     public int hashCode() {
-        return (elemID << 16) + attrID;
+        return (getElementID() << 16) + attrID;
     }
 
     public boolean equals(Object obj) {
         if (obj instanceof IndexPattern) {
             IndexPattern p = (IndexPattern) obj;
-            boolean eq = elemID == p.elemID && attrID == p.attrID;
+            boolean eq = Arrays.equals(elemID, p.elemID) && attrID == p.attrID && absolute == p.absolute;
             if (eq && (elemName != null || p.elemName != null)) {
-                eq = elemName != null && p.elemName != null && elemName.equals(p.elemName);
+                eq = elemName != null && p.elemName != null && Arrays.equals(elemName, p.elemName);
             }
             if (eq && (attrName != null || p.attrName != null)) {
                 eq = attrName != null && p.attrName != null && attrName.equals(p.attrName);
@@ -241,5 +310,25 @@
         } else {
             return false;
         }
+    }
+
+    public String toString() {
+        StringBuffer pattern = new StringBuffer();
+        if (absolute) {
+            pattern.append('/');
+        }
+
+        for (int i = 0; i < elemID.length; i++) {
+            pattern.append(elemName[i]);
+            if (i < elemID.length - 1) {
+                pattern.append('/');
+            }
+        }
+
+        if (attrID != PATTERN_NONE) {
+            pattern.append('@').append(attrName);
+        }
+
+        return pattern.toString();
     }
 }

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/MemValueIndexer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/MemValueIndexer.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/MemValueIndexer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/MemValueIndexer.java Sun Feb 17 18:33:55 2008
@@ -34,7 +34,6 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Map;
-import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -74,8 +73,6 @@
     private static final String NAME = "name";
     private static final String PATTERN = "pattern";
     private static final String TYPE = "type";
-    // private static final String PAGESIZE = "pagesize";
-    // private static final String MAXKEYSIZE = "maxkeysize";
 
     private static final String STRING_VAL = "string";
     private static final String TRIMMED_VAL = "trimmed";
@@ -95,9 +92,9 @@
     //
 
     /**
-     * TODO: Unused: the indexed Collection
-     private org.apache.xindice.core.Collection itsCollection;
+     * the indexed Collection
      */
+     private org.apache.xindice.core.Collection itsCollection;
 
     /**
      * this object's configuration
@@ -115,9 +112,9 @@
     private IndexPattern itsPattern;
 
     /**
-     * TODO: Unused: indicates if wildcard index
-     private boolean itsWildcard = false;
+     * indicates if wildcard index
      */
+     private boolean itsWildcard = false;
 
     /**
      * value type of this index
@@ -143,7 +140,6 @@
      * tracks the open/closed state for open(), close(), and isOpened()
      */
     private boolean itsOpen = false;
-    private org.apache.xindice.core.Collection itsCollection;
     private IndexerEventHandler handler;
 
 
@@ -167,14 +163,6 @@
         return STYLE_NODEVALUE;
     }
 
-    public void addDocument(Key key) throws DBException {
-
-    }
-
-    public void removeDocument(Key key) throws DBException {
-
-    }
-
     /**
      * Provides the pattern recognized by this Indexer.  Patterns
      * must be in the form of (elem|*)[@(attr|*)] to tell the IndexManager
@@ -209,7 +197,7 @@
      * @return The resulting matches
      */
     public synchronized IndexMatch[] queryMatches(IndexQuery theQuery) throws DBException {
-        IndexMatch[] aResult = null;
+        LinkedList aResult = new LinkedList();
 
         // get the list of Value objects from the query
         // there may be 1 value (unary operation e.g. not equals),
@@ -236,6 +224,7 @@
         Object aHighEndpoint = aMatchValueArray[aMatchValueArray.length - 1];
         Iterator aValueIterator;
         int anOperator = theQuery.getOperator();
+        IndexPattern queryPattern = theQuery.getPattern();
 
         // perform the requested matching type
         switch (anOperator) {
@@ -246,8 +235,7 @@
             case IndexQuery.EQ: // exact match
                 aLocatorSet = (TreeSet) itsValues.get(aLowEndpoint);
                 if (aLocatorSet != null) {
-                    aResult = new IndexMatch[aLocatorSet.size()];
-                    addMatches(aResult, 0, aLocatorSet);
+                    addMatches(aResult, aLocatorSet, queryPattern);
                 }
                 break;
 
@@ -256,26 +244,14 @@
                 TreeSet anExcludedLocatorSet = (TreeSet) itsValues.get(aLowEndpoint);
 
                 aValueIterator = itsValues.entrySet().iterator();
-                int aResultIndex = 0;
                 if (anExcludedLocatorSet == null) {
-                    // allocate return array to include all locators since none are excluded
-                    aResult = new IndexMatch[itsValueLocatorCount];
-
                     // iterate over the values adding locators for each to result
                     // no need to filter while iterating
                     while (aValueIterator.hasNext()) {
                         // iterate over locators for current value adding each to result
-                        Iterator aLocatorIterator = ((TreeSet) ((Map.Entry) aValueIterator.next()).getValue()).iterator();
-                        for (; aLocatorIterator.hasNext(); ++aResultIndex) {
-                            ValueLocator aLocator = (ValueLocator) aLocatorIterator.next();
-                            aResult[aResultIndex] = new IndexMatch(
-                                    aLocator.getKey(), aLocator.getPosition(), aLocator.getLength(), aLocator.getElementID(), aLocator.getAttributeID());
-                        }
+                        addMatches(aResult, (TreeSet) ((Map.Entry) aValueIterator.next()).getValue(), queryPattern);
                     }
                 } else {
-                    // allocate return array to include all locators except those attached to excluded value
-                    aResult = new IndexMatch[itsValueLocatorCount - anExcludedLocatorSet.size()];
-
                     // iterate over the values adding locators for each to result
                     // must filter out the locator set for the excluded value while iterating values
                     while (aValueIterator.hasNext()) {
@@ -284,12 +260,7 @@
                         // apply the exclusion filter for the matched value
                         if (aLocatorSet != anExcludedLocatorSet) {
                             // iterate over locators for current value adding each to result
-                            Iterator aLocatorIterator = ((TreeSet) ((Map.Entry) aValueIterator.next()).getValue()).iterator();
-                            for (; aLocatorIterator.hasNext(); ++aResultIndex) {
-                                ValueLocator aLocator = (ValueLocator) aLocatorIterator.next();
-                                aResult[aResultIndex] = new IndexMatch(
-                                        aLocator.getKey(), aLocator.getPosition(), aLocator.getLength(), aLocator.getElementID(), aLocator.getAttributeID());
-                            }
+                            addMatches(aResult, aLocatorSet, queryPattern);
                         }
                     }
                 }
@@ -322,17 +293,14 @@
 
                 // if low_endpoint >= high_endpoint, result is empty
                 aLowEndpoint = getNextValueOf(aLowEndpoint);
-                if (aLowEndpoint == null || ((Comparable) aLowEndpoint).compareTo(aHighEndpoint) >= 0) {
-                    // empty result
-                    aResult = new IndexMatch[0];
-                } else {
+                if (aLowEndpoint != null && ((Comparable) aLowEndpoint).compareTo(aHighEndpoint) < 0) {
                     // return locators in sub map exclusive of endpoints
-                    aResult = getIndexMatchArray(itsValues.subMap(aLowEndpoint, aHighEndpoint));
+                    addMatches(aResult, itsValues.subMap(aLowEndpoint, aHighEndpoint), queryPattern);
                 }
                 break;
 
             case IndexQuery.BW: // Between (Inclusive)
-                aResult = getIndexMatchArray(getBWSubmap(aLowEndpoint, aHighEndpoint));
+                addMatches(aResult, getBWSubmap(aLowEndpoint, aHighEndpoint), queryPattern);
                 break;
 
             case IndexQuery.SW: // starts-with
@@ -340,13 +308,12 @@
                 // always compare against the String form of the comparator
                 // to ensure that comparisons happen as Strings as specified by XPath
                 // for starts-with
-                if(! (aLowEndpoint instanceof String) )
-                {
+                if (! (aLowEndpoint instanceof String) ) {
                     aLowEndpoint = aLowEndpoint.toString();
                 }
 
                 // get the matching submap forcing String comparisons to be used regardless of stored type
-                aResult = getIndexMatchArray(getSWSubmap((String)aLowEndpoint));
+                addMatches(aResult, getSWSubmap((String)aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.IN: // In the (presumed sorted) set of specified query values
@@ -356,17 +323,19 @@
                 // the match high endpoint is at the top of the array (already set)
 
                 // get the matching submap forcing String comparisons to be used regardless of stored type
-                aResult = getIndexMatchArray(getBWSubmap(aLowEndpoint, aLowEndpoint), aMatchValueArray, false); // false => include style filtering applied
+                addMatches(aResult, getBWSubmap(aLowEndpoint, aHighEndpoint), aMatchValueArray, false, queryPattern); // false => include style filtering applied
                 break;
 
             case IndexQuery.NBWX: // Not between (Exclusive)
                 // implement as LT or GT
-                aResult = getIndexMatchArray(getLTSubmap(aLowEndpoint), getGTSubmap(aHighEndpoint));
+                addMatches(aResult, getLTSubmap(aLowEndpoint), queryPattern);
+                addMatches(aResult, getGTSubmap(aHighEndpoint), queryPattern);
                 break;
 
             case IndexQuery.NBW: // Not between (Inclusive)
                 // implement as LEQ or GEQ
-                aResult = getIndexMatchArray(getLEQSubmap(aLowEndpoint), getGEQSubmap(aHighEndpoint));
+                addMatches(aResult, getLEQSubmap(aLowEndpoint), queryPattern);
+                addMatches(aResult, getGEQSubmap(aHighEndpoint), queryPattern);
                 break;
 
             case IndexQuery.NSW: // Not starts-with
@@ -380,40 +349,43 @@
 
                 // get all matches below starts-with range and above starts-with range
                 // use of String key forces String matching
-                aResult = getIndexMatchArray(getLTSubmap(aLowEndpoint), getGTSubmap(aLowEndpoint));
+                addMatches(aResult, getLTSubmap(aLowEndpoint), queryPattern);
+                addMatches(aResult, getGTSubmap(aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.LT: // Less than
-                aResult = getIndexMatchArray(getLTSubmap(aLowEndpoint));
+                addMatches(aResult, getLTSubmap(aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.LEQ: // Less than or equal
-                aResult = getIndexMatchArray(getLEQSubmap(aLowEndpoint));
+                addMatches(aResult, getLEQSubmap(aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.GT: // Greater than
-                aResult = getIndexMatchArray(getGTSubmap(aLowEndpoint));
+                addMatches(aResult, getGTSubmap(aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.GEQ: // Greater than or equal
-                aResult = getIndexMatchArray(getGEQSubmap(aLowEndpoint));
+                addMatches(aResult, getGEQSubmap(aLowEndpoint), queryPattern);
                 break;
 
             case IndexQuery.NIN: // Not in specified set of query values
                 // scan all values excluding those specified in match value set
                 // includes all those entries LT the low endpoint, GT the high endpoint
                 // and the exclude-filtered set BW of the low and high endpoints
-                aResult = getIndexMatchArray(getLTSubmap(aLowEndpoint), getBWSubmap(aLowEndpoint, aLowEndpoint), // exclude-filter this
-                                             getGTSubmap(aHighEndpoint), aMatchValueArray, true); // true => exclude-style filtering applied
-
+                addMatches(aResult, getLTSubmap(aLowEndpoint), queryPattern);
+                addMatches(aResult, getGTSubmap(aHighEndpoint), queryPattern);
+                // exclude-filter this
+                // true => exclude-style filtering applied
+                addMatches(aResult, getBWSubmap(aLowEndpoint, aHighEndpoint), aMatchValueArray, true, queryPattern);
                 break;
 
             case IndexQuery.ANY: // return all values
-                aResult = getIndexMatchArray(itsValues);
+                addMatches(aResult, itsValues, queryPattern);
                 break;
         }
 
-        return aResult == null ? EMPTY_INDEX_MATCH_ARRAY : aResult;
+        return (IndexMatch[]) aResult.toArray(EMPTY_INDEX_MATCH_ARRAY);
     }
 
     /**
@@ -451,7 +423,6 @@
      */
     private SortedMap getBWSubmap(Object theLowEndpoint, Object theHighEndpoint) {
         SortedMap aSubmap = null;
-        TreeSet aLocatorSet;
 
         // anOperator == IndexQuery.BW
         int aComparison = ((Comparable) theLowEndpoint).compareTo(theHighEndpoint);
@@ -459,7 +430,7 @@
         if (aComparison == 0) {
             // low endpoint == high endpoint
             // return result set containing just the low endpoint matches, if any
-            aLocatorSet = (TreeSet) itsValues.get(theLowEndpoint);
+            TreeSet aLocatorSet = (TreeSet) itsValues.get(theLowEndpoint);
             if (aLocatorSet != null) {
                 aSubmap = new TreeMap(MemValueIndexer.ValueComparator.INSTANCE);
                 aSubmap.put(theLowEndpoint, aLocatorSet);
@@ -546,76 +517,26 @@
     }
 
     /**
-     * Provides an IndexMatch array containing IndexMatch objects
-     * for the locators in the specified Map.
-     *
-     * @param theMap Map containing Sets of ValueLocator objects as values
-     * @return a new array of IndexMatch objects
-     */
-    private IndexMatch[] getIndexMatchArray(Map theMap) {
-        IndexMatch[] aResult;
-
-        // count results to size result array
-        if (theMap != null) {
-            aResult = new IndexMatch[countLocators(theMap)];
-            // add the matches to the result array
-            addMatches(aResult, 0, theMap);
-        } else {
-            aResult = new IndexMatch[0];
-        }
-
-        return aResult;
-    }
-
-    /**
-     * Provides an IndexMatch array containing IndexMatch objects
-     * for the locators in the specified Maps. Results from theFirstMap
-     * will appear first in the array. Ordering is dependent on ordering
-     * of the map's iterators.
-     *
-     * @param theFirstMap Map containing Sets of ValueLocator objects as values
-     * @param theSecondMap Map containing Sets of ValueLocator objects as values
-     * @return a new array of IndexMatch objects
-     */
-    private IndexMatch[] getIndexMatchArray(Map theFirstMap, Map theSecondMap) {
-        int aLocatorCount = 0;
-
-        // count results to size result array
-        aLocatorCount += countLocators(theFirstMap);
-        aLocatorCount += countLocators(theSecondMap);
-
-        IndexMatch[] aResult = new IndexMatch[aLocatorCount];
-
-        aLocatorCount = 0;
-
-        aLocatorCount = addMatches(aResult, aLocatorCount, theFirstMap);
-        addMatches(aResult, aLocatorCount, theSecondMap);
-
-        return aResult;
-    }
-
-    /**
-     * Provides an IndexMatch array containing IndexMatch objects
-     * for the locators in the specified Map. If theExcludeFlag is
-     * true, all values in theFilterList will be excluded from the
-     * result. If theExcludeFlag is false, only values appearing in
-     * the theFilterList will be included in the result.
+     * Collects IndexMatch objects for the locators in the specified Map.
+     * If theExcludeFlag is true, all values in theFilterList will be
+     * excluded from the result. If theExcludeFlag is false, only values
+     * appearing in the theFilterList will be included in the result.
      *
+     * @param aResult list to store the matching document keys
      * @param theMap Map containing Sets of ValueLocator objects as values
      * @param theFilterList list of values to filter result (exclude or include filtering)
      * @param theExcludeFlag filtering is exclude if true, include if false
-     * @return a new array of IndexMatch objects
+     * @param queryPattern query index pattern
      */
-    private IndexMatch[] getIndexMatchArray(Map theMap, Object[] theFilterList, boolean theExcludeFlag) {
+    private void addMatches(LinkedList aResult, Map theMap, Object[] theFilterList, boolean theExcludeFlag, IndexPattern queryPattern) {
+
         if (theMap == null) {
-            return new IndexMatch[0];
+            return;
         }
 
         LinkedList aResultList = new LinkedList();
-        Iterator aValueIterator;
-        int aLocatorCount = 0;
 
-        aValueIterator = theMap.entrySet().iterator();
+        Iterator aValueIterator = theMap.entrySet().iterator();
 
         // iterate over the values adding locators for each matched to result
         while (aValueIterator.hasNext()) {
@@ -624,97 +545,18 @@
 
             boolean aValueInFilterList = Arrays.binarySearch(theFilterList, aKey, MemValueIndexer.ValueComparator.INSTANCE) >= 0;
 
-            if (theExcludeFlag && !aValueInFilterList || !theExcludeFlag && aValueInFilterList) {
+            if (theExcludeFlag ^ aValueInFilterList) {
                 // key passes filter => add to return
                 TreeSet aSet = (TreeSet) anEntry.getValue();
-                aLocatorCount += aSet.size();
                 aResultList.add(aSet);
             }
         }
 
-        IndexMatch[] aResult = new IndexMatch[aLocatorCount];
-
         // add the list of locators to the result
         aValueIterator = aResultList.iterator();
-        aLocatorCount = 0;
         while (aValueIterator.hasNext()) {
-            aLocatorCount = addMatches(aResult, aLocatorCount, (Collection) aValueIterator.next());
+            addMatches(aResult, (Collection) aValueIterator.next(), queryPattern);
         }
-
-        return aResult;
-    }
-
-    /**
-     * Provides an IndexMatch array containing IndexMatch objects
-     * for the locators in the specified Maps. Results from theFirstMap
-     * will appear first in the array. Results from theFilterThisMap
-     * will appear second in the array. Results from theThirdMap
-     * will appear third in the array. Ordering is dependent on ordering
-     * of the map's iterators. Include or Exclude filtering (depending on
-     * theExcludeFlag) will be applied to results from theFilterThisMap.
-     * Filtering will include or exclude values appearing in theFilterList.
-     *
-     * @param theFirstMap Map containing Sets of ValueLocator objects as values
-     * @param theFilterThisMap Map containing Sets of ValueLocator objects as values (will be filtered)
-     * @param theThirdMap Map containing Sets of ValueLocator objects as values
-     * @param theFilterList list of values to filter result (exclude or include filtering)
-     * @param theExcludeFlag filtering is exclude if true, include if false
-     * @return a new array of IndexMatch objects
-     */
-    private IndexMatch[] getIndexMatchArray(Map theFirstMap, Map theFilterThisMap, Map theThirdMap,
-                                            Object[] theFilterList, boolean theExcludeFlag) {
-        if (theFilterThisMap == null) {
-            return getIndexMatchArray(theFirstMap, theThirdMap);
-        }
-
-        LinkedList aResultList = new LinkedList();
-        Iterator aValueIterator;
-        int aLocatorCount = 0;
-
-        // count results to size result array
-        // count results to size result array
-        aLocatorCount += countLocators(theFirstMap);
-
-        // qualify the results for filter operation
-        // adding those qualifying to aResultCollection and counting filtered results
-        aValueIterator = theFirstMap.entrySet().iterator();
-
-        // iterate over the values adding locators for each matched to result
-        while (aValueIterator.hasNext()) {
-            Map.Entry anEntry = (Map.Entry) aValueIterator.next();
-            Object aKey = anEntry.getKey();
-
-            boolean aValueInFilterList = Arrays.binarySearch(theFilterList, aKey, MemValueIndexer.ValueComparator.INSTANCE) >= 0;
-
-            if (theExcludeFlag && !aValueInFilterList || !theExcludeFlag && aValueInFilterList) {
-                // key passes filter => add to return
-                TreeSet aSet = (TreeSet) anEntry.getValue();
-                aLocatorCount += aSet.size();
-                aResultList.add(aSet);
-            }
-        }
-
-        // count locators in third map
-        aLocatorCount += countLocators(theThirdMap);
-
-        // allocate array for combined results
-        IndexMatch[] aResult = new IndexMatch[aLocatorCount];
-
-        aLocatorCount = 0;
-
-        // add first map's contents to result
-        aLocatorCount = addMatches(aResult, aLocatorCount, theFirstMap);
-
-        // add the filtered list of locators to the result
-        aValueIterator = aResultList.iterator();
-        while (aValueIterator.hasNext()) {
-            aLocatorCount = addMatches(aResult, aLocatorCount, (Collection) aValueIterator.next());
-        }
-
-        // add the third map's contents to the result
-        addMatches(aResult, aLocatorCount, theThirdMap);
-
-        return aResult;
     }
 
     /**
@@ -741,7 +583,7 @@
         try {
             itsName = theConfig.getAttribute(NAME);
             String itsPattern = theConfig.getAttribute(PATTERN);
-            // TODO: Unused: itsWildcard = itsPattern.indexOf('*') != -1;
+            itsWildcard = itsPattern.indexOf('*') != -1;
 
             // Determine the Index Type
             String type = theConfig.getAttribute(TYPE, STRING_VAL).toLowerCase();
@@ -1112,40 +954,17 @@
     }
 
     /**
-     * Counts the number of ValueLocator objects
-     * stored in the TreeSet objects contained as values
-     * in the specified map. If theMap is null, 0 is returned.
-     *
-     * @param theMap map containing sets of ValueLocator objects to add as IndexMatches
-     * @return the count of ValueLocator objects
-     */
-    private int countLocators(Map theMap) {
-        int aCount = 0;
-
-        if (theMap != null) {
-            Iterator aValueIterator = theMap.entrySet().iterator();
-            // iterate over the values adding locators for each to result
-            // no need to filter while iterating
-            while (aValueIterator.hasNext()) {
-                aCount += ((Set) ((Map.Entry) aValueIterator.next()).getValue()).size();
-            }
-        }
-        return aCount;
-    }
-
-    /**
      * Adds the ValueLocators from the all the sets
      * of value locators found in the specified map
-     * as IndexMatches to the specified array of IndexMatches.
+     * as IndexMatches to the specified list of IndexMatches.
      *
-     * @param theArray array to add matches to
-     * @param theStartIndex index to start adding at
+     * @param theList list to add matches to
      * @param theMap map containing sets of ValueLocator objects to add as IndexMatches
-     * @return the next index beyond the last entry added
+     * @param queryPattern query index pattern
      */
-    private int addMatches(IndexMatch[] theArray, int theStartIndex, Map theMap) {
+    private void addMatches(LinkedList theList, Map theMap, IndexPattern queryPattern) {
         if (theMap == null) {
-            return theStartIndex;
+            return;
         }
 
         Iterator aValueIterator = theMap.entrySet().iterator();
@@ -1153,38 +972,36 @@
         // no need to filter while iterating
         while (aValueIterator.hasNext()) {
             // iterate over locators for current value adding each to result
-            Iterator aLocatorIterator = ((TreeSet) ((Map.Entry) aValueIterator.next()).getValue()).iterator();
-            for (; aLocatorIterator.hasNext(); ++theStartIndex) {
-                ValueLocator aLocator = (ValueLocator) aLocatorIterator.next();
-                theArray[theStartIndex] = new IndexMatch(
-                        aLocator.getKey(), aLocator.getPosition(), aLocator.getLength(), aLocator.getElementID(), aLocator.getAttributeID());
-            }
+            addMatches(theList, (TreeSet) ((Map.Entry) aValueIterator.next()).getValue(), queryPattern);
         }
-
-        return theStartIndex;
     }
 
     /**
      * Adds the ValueLocators from the specified set
-     * as IndexMatches to the specified array of IndexMatches.
+     * as IndexMatches to the specified list of IndexMatches.
      *
-     * @param theArray array to add matches to
-     * @param theStartIndex index to start adding at
+     * @param theList list to add matches to
      * @param theSet Set conatining ValueLocator objects to add as IndexMatches
-     * @return the next index beyond the last entry added
+     * @param queryPattern query index pattern
      */
-    private int addMatches(IndexMatch[] theArray, int theStartIndex, java.util.Collection theSet) {
+    private void addMatches(LinkedList theList, Collection theSet, IndexPattern queryPattern) {
         if (theSet == null) {
-            return theStartIndex;
+            return;
         }
 
-        Iterator aLocatorIterator = theSet.iterator();
-        for (; aLocatorIterator.hasNext(); ++theStartIndex) {
+        for (Iterator aLocatorIterator = theSet.iterator(); aLocatorIterator.hasNext(); ) {
             ValueLocator aLocator = (ValueLocator) aLocatorIterator.next();
-            theArray[theStartIndex] = new IndexMatch(
-                    aLocator.getKey(), aLocator.getPosition(), aLocator.getLength(), aLocator.getElementID(), aLocator.getAttributeID());
+            if (itsWildcard) {
+                IndexPattern matchElement = new IndexPattern(itsCollection.getSymbols(), aLocator.getElementID(), aLocator.getAttributeID());
+                IndexPattern queryElement = new IndexPattern(itsCollection.getSymbols(), queryPattern.getElementID(),
+                                                             queryPattern.getAttributeID());
+                if (matchElement.getMatchLevel(queryElement) > 0) {
+                    theList.add(new IndexMatch(aLocator.getKey(), aLocator.getElementID(), aLocator.getAttributeID()));
+                }
+            } else {
+                theList.add(new IndexMatch(aLocator.getKey(), aLocator.getElementID(), aLocator.getAttributeID()));
+            }
         }
-        return theStartIndex;
     }
 
     /**

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/NameIndexer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/NameIndexer.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/NameIndexer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/NameIndexer.java Sun Feb 17 18:33:55 2008
@@ -160,8 +160,9 @@
                 public boolean indexInfo(Value value, long pos) {
                     IndexMatch match = getIndexMatch(value);
                     if (wildcard) {
-                        IndexPattern pt = new IndexPattern(symbols, match.getElement(), match.getAttribute());
-                        if (pt.getMatchLevel(pattern) > 0) {
+                        IndexPattern matchElement = new IndexPattern(symbols, match.getElement(), match.getAttribute());
+                        IndexPattern queryElement = new IndexPattern(symbols, pattern.getElementID(), pattern.getAttributeID());
+                        if (matchElement.getMatchLevel(queryElement) > 0) {
                             results.add(match);
                         }
                     } else {

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/ValueIndexer.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/ValueIndexer.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/ValueIndexer.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/indexer/ValueIndexer.java Sun Feb 17 18:33:55 2008
@@ -409,13 +409,15 @@
                     try {
                         if (pos == MATCH_INFO) {
                             IndexMatch match = getIndexMatch(value);
-                            if (!wildcard)
-                                results.add(match);
-                            else {
-                                IndexPattern pt = new IndexPattern(symbols, match.getElement(), match.getAttribute());
-                                if (pt.getMatchLevel(query.getPattern()) > 0) {
+                            if (wildcard) {
+                                IndexPattern matchElement = new IndexPattern(symbols, match.getElement(), match.getAttribute());
+                                IndexPattern queryElement = new IndexPattern(symbols, query.getPattern().getElementID(),
+                                                                             query.getPattern().getAttributeID());
+                                if (matchElement.getMatchLevel(queryElement) > 0) {
                                     results.add(match);
                                 }
+                            } else {
+                                results.add(match);
                             }
                         } else {
                             BTreeRootInfo root = new BTreeRootInfo(value, pos);

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java Sun Feb 17 18:33:55 2008
@@ -90,6 +90,7 @@
 import java.util.TreeSet;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.LinkedList;
 
 /**
  * XPathQueryResolver
@@ -237,7 +238,7 @@
         }
     }
 
-	/**
+    /**
      * XPathQuery
      */
     private class XPathQuery implements Query {
@@ -306,8 +307,8 @@
             return keys;
         }
 
-		public NodeSet execute() throws QueryException {
-			try {
+        public NodeSet execute() throws QueryException {
+            try {
                 Key[] keySet = keys;
 
                 // TODO: Add logic to do an indexed check on provided
@@ -360,7 +361,7 @@
 
         // Evaluation Methods
 
-		/**
+        /**
          * evaluate does a partial evaluation of the XPath in order to
          * determine the optimal indexes to prepare for the query and retrieve
          * the Document subset that will be used for the actual XPath query.
@@ -379,13 +380,13 @@
          * @param pos   The position to start at (recursively called)
          * @return Some Object result
          */
-        private Object evaluate(String owner, int pos) throws Exception {
+        private Object evaluate(NodePath owner, int pos) throws Exception {
             int op = cmp.getOp(pos);
             if (op == -1) {
                 return null;
             }
 
-			switch (op) {
+            switch (op) {
                 case OpCodes.OP_LOCATIONPATH:
                     return evalLocationPath(owner, pos);
 
@@ -478,55 +479,31 @@
             return null;
         }
 
-		private Object evalLocationPath(String owner, int pos) throws Exception {
+        private Object evalLocationPath(NodePath owner, int pos) throws Exception {
             int lp = Compiler.getFirstChildPos(pos);
             List ks = new ArrayList();
 
-            String name = owner;
+            NodePath name = owner != null ? new NodePath(owner) : new NodePath();
             boolean attr = false;
-			while (cmp.getOp(lp) != -1) {
+            while (cmp.getOp(lp) != -1) {
                 Object obj = evaluate(name, lp);
-				if (obj instanceof NamedKeys) {
+                if (obj instanceof NamedKeys) {
                     NamedKeys nk = (NamedKeys) obj;
                     if (nk.name != null) {
                         attr = nk.attribute;
-                        if (attr) {
-                            if (name == null) {
-                                name = owner;
-                            }
-                            if (name != null) {
-                                StringBuffer sb = new StringBuffer(32);
-                                sb.append(name);
-                                sb.append('@');
-                                sb.append(nk.name);
-                                name = sb.toString();
-                            }
-                        } else {
-                            name = nk.name;
-                        }
+                        name = nk.name;
                     }
-					if (nk.keys != null) {
+
+                    if (nk.keys != null) {
                         ks.add(nk.keys);
-                    }
-                    else if (name != null) {
+                    } else if (name != null && !name.isEmpty()) {
                         // Try to use a NameIndex to resolve the path component
-                        // can match a wildcard node name here if pattern is "*" then every document matches
-                        if (!attr && "*".equals(name)) {
-                            SortedSet set = new TreeSet();
-                            RecordSet rs = context.getFiler().getRecordSet();
-                            while (rs.hasMoreRecords()) {
-                                set.add(rs.getNextKey());
-                            }
-                            ks.add(set.toArray(EMPTY_KEYS));
-                        } else {
-                            // Try to use a NameIndex to resolve the path component
-                            IndexPattern pattern = new IndexPattern(symbols, name, nsMap);
-                            Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODENAME, pattern);
-                            if (idx != null) {
-                                IndexMatch[] matches = idx.queryMatches(new IndexQueryANY(pattern));
-                                Key[] keys = QueryEngine.getUniqueKeys(matches);
-                                ks.add(keys);
-                            }
+                        IndexPattern pattern = new IndexPattern(symbols, name.toString(), nsMap);
+                        Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODENAME, pattern);
+                        if (idx != null) {
+                            IndexMatch[] matches = idx.queryMatches(new IndexQueryANY(pattern));
+                            Key[] keys = QueryEngine.getUniqueKeys(matches);
+                            ks.add(keys);
                         }
                     }
                 }
@@ -535,7 +512,7 @@
             return new NamedKeys(name, attr, andKeys(ks));
         }
 
-        private Object evalUnion(String owner, int pos) throws Exception {
+        private Object evalUnion(NodePath owner, int pos) throws Exception {
             int l = Compiler.getFirstChildPos(pos);
             int r = cmp.getNextOpPos(l);
             Object left = evaluate(owner, l);
@@ -551,16 +528,16 @@
 
             // no index query of left part of union
             // or no index query of right part of union => must do
-            /// collection scan
+            // collection scan
             return null;
         }
 
-		private Object evalSetComparison(int op, String owner, int pos) throws Exception {
+        private Object evalSetComparison(int op, NodePath owner, int pos) throws Exception {
             int l = Compiler.getFirstChildPos(pos);
             int r = cmp.getNextOpPos(l);
             Object left = evaluate(owner, l);
 
-			if (left instanceof NamedKeys && ((NamedKeys) left).keys != null) {
+            if (left instanceof NamedKeys && ((NamedKeys) left).keys != null) {
                 // have left keys
                 if (((NamedKeys) left).keys.length == 0 && op == OpCodes.OP_AND) {
                     // left keyset empty implies result of AND would be empty
@@ -568,9 +545,9 @@
                 }
 
                 Object right = evaluate(owner, r);
-				if (right instanceof NamedKeys && ((NamedKeys) right).keys != null) {
+                if (right instanceof NamedKeys && ((NamedKeys) right).keys != null) {
                     // have keys for both left and right
-					if (op == OpCodes.OP_AND) {
+                    if (op == OpCodes.OP_AND) {
                         if (((NamedKeys) right).keys.length == 0) {
                             // right keyset empty implies result of AND would be empty
                             return new NamedKeys(null, false, ((NamedKeys) right).keys);
@@ -616,7 +593,7 @@
             return null;
         }
 
-        private Object evalValComparison(int op, String owner, int pos) throws Exception {
+        private Object evalValComparison(int op, NodePath owner, int pos) throws Exception {
             int l = Compiler.getFirstChildPos(pos);
             int r = cmp.getNextOpPos(l);
 
@@ -628,7 +605,7 @@
 
             Object right = evaluate(owner, r);
             if ((left instanceof NamedKeys && right instanceof XObject)
-                    || (left instanceof XObject && right instanceof NamedKeys)) {
+                || (left instanceof XObject && right instanceof NamedKeys)) {
                 // try to evaluate through indexed search
                 return queryComparison(op, owner, left, right);
             }
@@ -660,7 +637,7 @@
             return null;
         }
 
-        private strictfp Object evalMathOperation(int op, String owner, int pos) throws Exception {
+        private strictfp Object evalMathOperation(int op, NodePath owner, int pos) throws Exception {
             int lc = Compiler.getFirstChildPos(pos);
             int rc = cmp.getNextOpPos(lc);
             Object left = evaluate(owner, lc);
@@ -691,7 +668,7 @@
             return null;
         }
 
-        private Object evalUnaryOperation(int op, String owner, int pos) throws Exception {
+        private Object evalUnaryOperation(int op, NodePath owner, int pos) throws Exception {
             Object val = evaluate(owner, Compiler.getFirstChildPos(pos));
             if (val instanceof XObject) {
                 switch (op) {
@@ -721,7 +698,7 @@
             return null;
         }
 
-        private Object evalFunction(String owner, int pos) throws Exception {
+        private Object evalFunction(NodePath owner, int pos) throws Exception {
             int idx = Compiler.getFirstChildPos(pos);
             int id = cmp.getOp(idx);
 
@@ -790,7 +767,7 @@
             }
         }
 
-        private Object evalAxis(int op, String owner, int pos) throws Exception {
+        private Object evalAxis(int op, NodePath owner, int pos) throws Exception {
             String nsURI = cmp.getStepNS(pos);
             String name = (String) evaluate(owner, Compiler.getFirstChildPosOfStep(pos));
             // owner = cmp.getStepLocalName(pos);
@@ -811,18 +788,12 @@
                     StringBuffer sb = new StringBuffer(32);
                     sb.append(pfx);
                     sb.append(':');
-                    sb.append(owner);
+                    sb.append(name);
                     name = sb.toString();
                 }
             }
 
-            if (op == OpCodes.FROM_ATTRIBUTES) {
-                owner = owner + '@' + name;
-            } else if (op == OpCodes.FROM_SELF && WILDCARD.equals(name)) {
-                name = owner;
-            } else {
-                owner = name;
-            }
+            owner.makeStep(op, name);
 
             int rp = cmp.getFirstPredicateOpPos(pos);
 
@@ -837,10 +808,10 @@
                 }
                 rp = cmp.getNextOpPos(rp);
             }
-            return new NamedKeys(name, (op == OpCodes.FROM_ATTRIBUTES), andKeys(ks));
+            return new NamedKeys(owner, (op == OpCodes.FROM_ATTRIBUTES), andKeys(ks));
         }
 
-        private Object evalLiteral(String owner, int pos) {
+        private Object evalLiteral(NodePath owner, int pos) {
             int idx = cmp.getOp(Compiler.getFirstChildPos(pos));
             switch (idx) {
                 case OpCodes.EMPTY:
@@ -918,7 +889,7 @@
             return null;
         }
 
-        private Object funcFTContains(String owner, List args) throws Exception {
+        private Object funcFTContains(NodePath owner, List args) throws Exception {
             if (args.size() != 1) {
                 return null;
             }
@@ -934,7 +905,7 @@
                 String query = ((XString) o).str();
                 return queryTextIndex(owner, query);
             }
-            
+
             return null;
         }
 
@@ -1006,7 +977,7 @@
             return null;
         }
 
-        private Object funcStartsWith(String owner, List args) throws Exception {
+        private Object funcStartsWith(NodePath owner, List args) throws Exception {
             if (args.size() == 2) {
                 Object o = args.get(0);
                 Object s = args.get(1);
@@ -1021,10 +992,10 @@
                     NamedKeys nk = (NamedKeys) o;
                     if (nk.name != null) {
                         String ps;
-                        if (nk.attribute && nk.name.indexOf('@') == -1) {
+                        if (nk.attribute && nk.name.attr == null) {
                             ps = owner + "@" + nk.name;
                         } else {
-                            ps = nk.name;
+                            ps = nk.name.toString();
                         }
 
                         IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
@@ -1129,7 +1100,7 @@
 
         // The Actual Querying Methods
 
-		/**
+        /**
          * queryIndexes actually performs index-based querying on behalf of the evaluation methods.
          *
          * @param nk      The NamedKeys instance to use for matches
@@ -1139,7 +1110,7 @@
          * @return The resulting Keys (if any)
          */
         private Object queryIndexes(NamedKeys nk, IndexQuery iq, String ps, int objType) {
-			try {
+            try {
                 // TODO: Add logic to use an EmptyKeySet if a name doesn't already
                 //       exist in the SymbolTable.  This will eliminate the need
                 //       to do a collection scan in those cases where somebody
@@ -1148,7 +1119,7 @@
                 IndexPattern pattern = iq.getPattern();
 
                 Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODEVALUE, pattern);
-				if (idx != null) {
+                if (idx != null) {
                     return new NamedKeys(nk.name, nk.attribute, QueryEngine.getUniqueKeys(idx.queryMatches(iq)));
                 } else if (autoIndex) {
                     // TODO: This has to *not* be hardcoded
@@ -1195,8 +1166,8 @@
             return null;
         }
 
-        private Object queryTextIndex(String ps, String query) throws Exception {
-            IndexPattern pattern = new IndexPattern(symbols, ps, nsMap);
+        private Object queryTextIndex(NodePath ps, String query) throws Exception {
+            IndexPattern pattern = new IndexPattern(symbols, ps.toString(), nsMap);
 
             // check if there is full text indexer for this collection
             Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_FULLTEXT, pattern);
@@ -1224,7 +1195,7 @@
                     IndexMatch[] matches = textInd.queryMatches(parsedQuery);
                     Key[] keys = QueryEngine.getUniqueKeys(matches);
 
-                    return new NamedKeys(ps, ps.indexOf('@') != -1, keys);
+                    return new NamedKeys(ps, ps.attr != null, keys);
                 }
             } else {
                 // there is no Lucene indexer, fall back to default analyzer
@@ -1246,7 +1217,7 @@
          * @param right The right Operand
          * @return The resulting Keys (if any)
          */
-        private Object queryComparison(int op, String owner, Object left, Object right) throws Exception {
+        private Object queryComparison(int op, NodePath owner, Object left, Object right) throws Exception {
             op = OPMAP[op - OpCodes.OP_NOTEQUALS];
 
             if (left instanceof XObject) {
@@ -1270,10 +1241,10 @@
 
             if (nk.name != null) {
                 String ps;
-                if (nk.attribute && nk.name.indexOf('@') == -1) {
+                if (nk.attribute && nk.name.attr == null) {
                     ps = owner + "@" + nk.name;
                 } else {
-                    ps = nk.name;
+                    ps = nk.name.toString();
                 }
 
                 IndexQuery iq;
@@ -1316,17 +1287,17 @@
 
     private class NamedKeys {
         public boolean attribute = false;
-        public String name;
+        public NodePath name;
         public Key[] keys;
 
-        public NamedKeys(String name, boolean attribute, Key[] keys) {
+        public NamedKeys(NodePath name, boolean attribute, Key[] keys) {
             this.name = name;
             this.attribute = attribute;
             this.keys = keys;
         }
     }
 
-	/**
+    /**
      * ResultSet
      */
 
@@ -1394,7 +1365,7 @@
         private void prepareNextNode() throws XMLDBException, TransformerException, DBException {
             node = null;
 
-			while (keyPos < keySet.length) {
+            while (keyPos < keySet.length) {
                 final Key key = keySet[keyPos++];
 
                 Entry entry = context.getEntry(key);
@@ -1425,7 +1396,7 @@
                 }
 
                 final XObject xobject = xp.execute(xpc, n, pfx);
-				switch (xobject.getType()) {
+                switch (xobject.getType()) {
                     // case XObject.CLASS_RTREEEFRAG :
                     default :
                         throw new XMLDBException(ErrorCodes.NOT_IMPLEMENTED,
@@ -1490,7 +1461,7 @@
         }
     }
 
-	/* This only implements what we need internally */
+    /* This only implements what we need internally */
     private static class EmptyNodeIterator implements NodeIterator {
 
         /* (non-Javadoc)
@@ -1561,6 +1532,101 @@
 
         public void setParameter(String name, Object object) {
             parameters.put(name, object);
+        }
+    }
+
+    /**
+     * Helper class to track path to a node in the XPath expression
+     */
+    private class NodePath {
+        private boolean absolute = false;
+        private LinkedList path = new LinkedList();
+        private String attr;
+
+        public NodePath() {
+        }
+
+        // copy constructor
+        public NodePath(NodePath copy) {
+            absolute = copy.absolute;
+            attr = copy.attr;
+            path = (LinkedList) copy.path.clone();
+        }
+
+        public void makeStep(int op, String name) {
+            switch (op) {
+                case OpCodes.FROM_ATTRIBUTES:
+                    attr = name;
+                    break;
+                case OpCodes.FROM_CHILDREN:
+                    path.addLast(name);
+                    break;
+                case OpCodes.FROM_ROOT:
+                    absolute = true;
+                    path.clear();
+                    break;
+                case OpCodes.FROM_DESCENDANTS_OR_SELF:
+                case OpCodes.FROM_ANCESTORS_OR_SELF:
+                    absolute = false;
+                    path.clear();
+                    if (!WILDCARD.equals(name)) {
+                        path.addLast(name);
+                    }
+                    break;
+                case OpCodes.FROM_PRECEDING:
+                case OpCodes.FROM_FOLLOWING:
+                case OpCodes.FROM_ANCESTORS:
+                case OpCodes.FROM_DESCENDANTS:
+                    absolute = false;
+                    path.clear();
+                    path.addLast(name);
+                    break;
+                case OpCodes.FROM_PARENT:
+                    if (path.size() > 0) {
+                        path.removeLast();
+                    }
+                    if (!WILDCARD.equals(name)) {
+                        if (path.size() > 0) {
+                            path.removeLast();
+                        }
+                        path.addLast(name);
+                    }
+                    break;
+                case OpCodes.FROM_FOLLOWING_SIBLINGS:
+                case OpCodes.FROM_PRECEDING_SIBLINGS:
+                case OpCodes.FROM_SELF:
+                    if (!WILDCARD.equals(name)) {
+                        if (path.size() > 0) {
+                            path.removeLast();
+                        }
+                        path.addLast(name);
+                    }
+                    break;
+                case OpCodes.FROM_NAMESPACE:
+                    absolute = false;
+                    path.clear();
+                    break;
+            }
+        }
+
+        public boolean isEmpty() {
+            return path.size() == 0;
+        }
+
+        public String toString() {
+            StringBuffer buf = absolute ? new StringBuffer("/") : new StringBuffer();
+            for (Iterator i = path.iterator(); i.hasNext(); ) {
+                buf.append(i.next());
+                if (i.hasNext()) {
+                    buf.append('/');
+                }
+            }
+
+            if (attr != null) {
+                buf.append('@').append(attr);
+            }
+
+            return buf.toString();
         }
     }
 }

Added: xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java?rev=628599&view=auto
==============================================================================
--- xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java (added)
+++ xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java Sun Feb 17 18:33:55 2008
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ *
+ * $Id$
+ */
+
+package org.apache.xindice.core.indexer;
+
+import junit.framework.TestCase;
+import org.apache.xindice.xml.SymbolTable;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Tests for IndexPattern.
+ *
+ * @version $Revision$, $Date$
+ */
+public class IndexPatternTest extends TestCase {
+    private SymbolTable symbols;
+    private IndexPattern[] testPatterns;
+
+    protected void setUp() throws Exception {
+        symbols = new SymbolTable();
+
+        testPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "c@d", null),
+                new IndexPattern(symbols, "c@*", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+                new IndexPattern(symbols, "/b/c@d", null),
+        };
+    }
+
+    public void testAbsolutePattern() throws Exception {
+        IndexPattern ip = new IndexPattern(symbols, "/a/b/c", null);
+
+        short[] elements = new short[] {
+                symbols.getSymbol("a"),
+                symbols.getSymbol("b"),
+                symbols.getSymbol("c"),
+        };
+        assertEquals("Absolute path", true, ip.isAbsolute());
+        assertTrue("Pattern elements are incorrect", Arrays.equals(elements, ip.getElementIDs()));
+        assertEquals("Pattern attribute is incorrect", IndexPattern.PATTERN_NONE, ip.getAttributeID());
+    }
+
+    public void testRelativePattern() throws Exception {
+        IndexPattern ip = new IndexPattern(symbols, "a/b/c", null);
+
+        short[] elements = new short[] {
+                symbols.getSymbol("a"),
+                symbols.getSymbol("b"),
+                symbols.getSymbol("c"),
+        };
+        assertEquals("Relative path", false, ip.isAbsolute());
+        assertTrue("Pattern elements are incorrect", Arrays.equals(elements, ip.getElementIDs()));
+        assertEquals("Pattern attribute is incorrect", IndexPattern.PATTERN_NONE, ip.getAttributeID());
+    }
+
+    public void testAbsolutePatternWithAttribute() throws Exception {
+        IndexPattern ip = new IndexPattern(symbols, "/a/b/c@d", null);
+
+        short[] elements = new short[] {
+                symbols.getSymbol("a"),
+                symbols.getSymbol("b"),
+                symbols.getSymbol("c"),
+        };
+        assertEquals("Absolute path", true, ip.isAbsolute());
+        assertTrue("Pattern elements are incorrect", Arrays.equals(elements, ip.getElementIDs()));
+        assertEquals("Pattern attribute is incorrect", symbols.getSymbol("d"), ip.getAttributeID());
+    }
+
+    public void testRelativePatternWithAttribute() throws Exception {
+        IndexPattern ip = new IndexPattern(symbols, "a/b/c@d", null);
+
+        short[] elements = new short[] {
+                symbols.getSymbol("a"),
+                symbols.getSymbol("b"),
+                symbols.getSymbol("c"),
+        };
+        assertEquals("Relative path", false, ip.isAbsolute());
+        assertTrue("Pattern elements are incorrect", Arrays.equals(elements, ip.getElementIDs()));
+        assertEquals("Pattern attribute is incorrect", symbols.getSymbol("d"), ip.getAttributeID());
+    }
+
+    public void testAbsolutePatternMatch() throws Exception {
+        IndexPattern pattern = new IndexPattern(symbols, "/a/b/c@d", null);
+
+        IndexPattern[] orderedPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "/b/c@d", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "c@*", null),
+                new IndexPattern(symbols, "c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+        };
+
+        Arrays.sort(testPatterns, getComparator(pattern));
+        assertTrue(Arrays.equals(testPatterns, orderedPatterns));
+    }
+
+    public void testShortAbsolutePatternMatch() throws Exception {
+        final IndexPattern pattern = new IndexPattern(symbols, "/c@d", null);
+
+        IndexPattern[] orderedPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+                new IndexPattern(symbols, "/b/c@d", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "c@*", null),
+                new IndexPattern(symbols, "c@d", null),
+        };
+
+        Arrays.sort(testPatterns, getComparator(pattern));
+        assertTrue(Arrays.equals(testPatterns, orderedPatterns));
+    }
+
+    public void testRelativePatternMatch() throws Exception {
+        final IndexPattern pattern = new IndexPattern(symbols, "b/c@d", null);
+
+        IndexPattern[] orderedPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+                new IndexPattern(symbols, "/b/c@d", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "c@*", null),
+                new IndexPattern(symbols, "c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+        };
+
+        Arrays.sort(testPatterns, getComparator(pattern));
+        assertTrue(Arrays.equals(testPatterns, orderedPatterns));
+    }
+
+    public void testShortRelativePatternMatch() throws Exception {
+        final IndexPattern pattern = new IndexPattern(symbols, "c@d", null);
+
+        IndexPattern[] orderedPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+                new IndexPattern(symbols, "/b/c@d", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "c@*", null),
+                new IndexPattern(symbols, "c@d", null),
+        };
+
+        Arrays.sort(testPatterns, getComparator(pattern));
+        assertTrue(Arrays.equals(testPatterns, orderedPatterns));
+    }
+
+    public void testWildcardPatternMatch() throws Exception {
+        final IndexPattern pattern = new IndexPattern(symbols, "c@*", null);
+
+        IndexPattern[] orderedPatterns = new IndexPattern[] {
+                new IndexPattern(symbols, "c@d", null),
+                new IndexPattern(symbols, "*@d", null),
+                new IndexPattern(symbols, "/a/b/*@d", null),
+                new IndexPattern(symbols, "/a/*/c@d", null),
+                new IndexPattern(symbols, "b/c@d", null),
+                new IndexPattern(symbols, "/a/b/c@d", null),
+                new IndexPattern(symbols, "/b/c@d", null),
+                new IndexPattern(symbols, "*@*", null),
+                new IndexPattern(symbols, "c@*", null),
+        };
+
+        Arrays.sort(testPatterns, getComparator(pattern));
+        assertTrue(Arrays.equals(testPatterns, orderedPatterns));
+    }
+
+    public void testToString() throws IndexerException {
+        String[] patterns = new String[] {
+                "c@d",
+                "c@*",
+                "*@*",
+                "*@d",
+                "/a/b/*@d",
+                "/a/*/c@d",
+                "b/c@d",
+                "/a/b/c@d",
+                "/b/c@d",
+        };
+
+        for (int i = 0; i < patterns.length; i++) {
+            assertEquals(patterns[i], new IndexPattern(symbols, patterns[i], null).toString());
+        }
+    }
+
+    private Comparator getComparator(final IndexPattern pattern) {
+        return new Comparator() {
+            public int compare(Object o1, Object o2) {
+                return pattern.getMatchLevel((IndexPattern) o1) - pattern.getMatchLevel((IndexPattern) o2);
+            }
+        };
+    }
+}

Propchange: xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/IndexPatternTest.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision Author Date

Modified: xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/LuceneIndexerTest.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/LuceneIndexerTest.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/LuceneIndexerTest.java (original)
+++ xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/LuceneIndexerTest.java Sun Feb 17 18:33:55 2008
@@ -115,8 +115,8 @@
     public void testDuplicate() throws Exception {
         try {
             HashMap patterns = new HashMap();
-            patterns.put("test1", "a@*");
-            patterns.put("test2", "b@*");
+            patterns.put("test1", "a");
+            patterns.put("test2", "b");
             createIndex("test1", patterns, null);
             createIndex("test2", patterns, null);
             fail("There can be only one full text index per collection");
@@ -127,8 +127,8 @@
 
     public void testMultipleIndexes() throws Exception {
         HashMap patterns = new HashMap();
-        patterns.put("test1", "a@*");
-        patterns.put("test2", "b@*");
+        patterns.put("test1", "a");
+        patterns.put("test2", "b");
         LuceneIndexer idx = createIndex("test", patterns, "test1");
 
         IndexMatch[] match = query(idx, "test");

Modified: xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/NameIndexerTest.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/NameIndexerTest.java?rev=628599&r1=628598&r2=628599&view=diff
==============================================================================
--- xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/NameIndexerTest.java (original)
+++ xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/NameIndexerTest.java Sun Feb 17 18:33:55 2008
@@ -149,4 +149,38 @@
         assertEquals(1, match.length);
     }
 
+    public void testElementAbsolutePathIndex() throws Exception {
+        Indexer ind = createIndex("index", "/a/test");
+
+        Document document = DOMParser.toDocument("<a><test>q</test></a>");
+        collection.insertDocument("key1", document);
+
+        document = DOMParser.toDocument("<a><test/></a>");
+        collection.insertDocument("key2", document);
+
+        document = DOMParser.toDocument("<b><test value='abc'/></b>");
+        collection.insertDocument("key3", document);
+
+        IndexMatch[] match = query(ind, "/a/test");
+
+        assertEquals(2, match.length);
+    }
+
+    public void testElementRelativePathIndex() throws Exception {
+        Indexer ind = createIndex("index", "test");
+
+        Document document = DOMParser.toDocument("<a><test>q</test></a>");
+        collection.insertDocument("key1", document);
+
+        document = DOMParser.toDocument("<a><test/></a>");
+        collection.insertDocument("key2", document);
+
+        document = DOMParser.toDocument("<b><test value='abc'/></b>");
+        collection.insertDocument("key3", document);
+
+        // index pattern is more general and therefore will return keys that not necesserily match the query
+        IndexMatch[] match = query(ind, "/a/test");
+
+        assertEquals(3, match.length);
+    }
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.