You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ak...@apache.org on 2008/03/28 00:13:39 UTC

svn commit: r642020 - in /directory/sandbox/akarasulu/bigbang/apacheds: core-cursor/src/main/java/org/apache/directory/server/core/cursor/ xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/

Author: akarasulu
Date: Thu Mar 27 16:13:30 2008
New Revision: 642020

URL: http://svn.apache.org/viewvc?rev=642020&view=rev
Log:
adding disjunction (OR) cursor implementation using blacklists

Added:
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/EvaluatorBuilder.java
      - copied, changed from r640704, directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java   (contents, props changed)
      - copied, changed from r640704, directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluator.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/OrCursor.java
Removed:
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluator.java
Modified:
    directory/sandbox/akarasulu/bigbang/apacheds/core-cursor/src/main/java/org/apache/directory/server/core/cursor/AbstractCursor.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/CursorBuilder.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionCursorBuilder.java
    directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/LeafEvaluator.java

Modified: directory/sandbox/akarasulu/bigbang/apacheds/core-cursor/src/main/java/org/apache/directory/server/core/cursor/AbstractCursor.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/core-cursor/src/main/java/org/apache/directory/server/core/cursor/AbstractCursor.java?rev=642020&r1=642019&r2=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/core-cursor/src/main/java/org/apache/directory/server/core/cursor/AbstractCursor.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/core-cursor/src/main/java/org/apache/directory/server/core/cursor/AbstractCursor.java Thu Mar 27 16:13:30 2008
@@ -48,7 +48,7 @@
     }
 
 
-    public void close()
+    public void close() throws Exception
     {
         closed = true;
     }

Modified: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/CursorBuilder.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/CursorBuilder.java?rev=642020&r1=642019&r2=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/CursorBuilder.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/CursorBuilder.java Thu Mar 27 16:13:30 2008
@@ -41,5 +41,5 @@
      * @return an enumeration over the 
      * @throws Exception if database access fails
      */
-    Cursor<IndexEntry<V,E>> enumerate( ExprNode node ) throws Exception;
+    Cursor<IndexEntry<V,E>> build( ExprNode node ) throws Exception;
 }

Modified: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java?rev=642020&r1=642019&r2=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java Thu Mar 27 16:13:30 2008
@@ -25,9 +25,7 @@
 
 
 /**
- * Tests if an entry is eligable for return by evaluating a filter expression on
- * the candidate.  The evaluation can proceed by applying the filter on the 
- * attributes of the entry itself or indices can be used for rapid evaluation.
+ * Evaluates candidate entries to see if they match a filter expression.
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$
@@ -37,10 +35,17 @@
     /**
      * Evaluates a candidate to determine if a filter expression selects it.
      * 
-     * @param node the filter expression to evaluate on the candidate
      * @param entry the index record of the entry to evaluate
-     * @return true if the filter selects the candidate false otherwise
-     * @throws Exception if there is a database fault during evaluation
+     * @return true if filter selects the candidate false otherwise
+     * @throws Exception if there are database faults during evaluation
      */
-    boolean evaluate( ExprNode node, IndexEntry<Long,E> entry ) throws Exception;
+    boolean evaluate( IndexEntry<?,E> entry ) throws Exception;
+
+
+    /**
+     * Gets the expression used by this expression Evaluator.
+     *
+     * @return the AST for the expression
+     */
+    ExprNode getExpression();
 }

Copied: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/EvaluatorBuilder.java (from r640704, directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java)
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/EvaluatorBuilder.java?p2=directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/EvaluatorBuilder.java&p1=directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java&r1=640704&r2=642020&rev=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/Evaluator.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/EvaluatorBuilder.java Thu Mar 27 16:13:30 2008
@@ -21,26 +21,23 @@
 
 
 import org.apache.directory.shared.ldap.filter.ExprNode;
-import org.apache.directory.server.xdbm.IndexEntry;
 
 
 /**
- * Tests if an entry is eligable for return by evaluating a filter expression on
- * the candidate.  The evaluation can proceed by applying the filter on the 
- * attributes of the entry itself or indices can be used for rapid evaluation.
- * 
+ * Builds a filter expression evaluator which checks if candidates match an
+ * expression filter.
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface Evaluator<E>
+public interface EvaluatorBuilder<E>
 {
     /**
-     * Evaluates a candidate to determine if a filter expression selects it.
-     * 
-     * @param node the filter expression to evaluate on the candidate
-     * @param entry the index record of the entry to evaluate
-     * @return true if the filter selects the candidate false otherwise
-     * @throws Exception if there is a database fault during evaluation
+     * Builds an Evaluator based on the filter expression provided.
+     *
+     * @param expression the filter expression AST
+     * @return the evaluator for the AST
+     * @throws Exception on database faults during construction
      */
-    boolean evaluate( ExprNode node, IndexEntry<Long,E> entry ) throws Exception;
-}
+    Evaluator<E> build( ExprNode expression ) throws Exception;
+}
\ No newline at end of file

Modified: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionCursorBuilder.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionCursorBuilder.java?rev=642020&r1=642019&r2=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionCursorBuilder.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionCursorBuilder.java Thu Mar 27 16:13:30 2008
@@ -65,23 +65,23 @@
     private ScopeCursorBuilder<E> scopeEnumerator;
     /** CursorBuilder flyweight for evaulating filter substring assertions */
     private SubstringCursorBuilder<E> substringEnumerator;
-    /** Evaluator dependency on a ExpressionEvaluator */
-    private ExpressionEvaluator<E> evaluator;
+    /** Evaluator dependency on a ExpressionEvaluatorBuilder */
+    private ExpressionEvaluatorBuilder<E> evaluatorBuilder;
 
 
     /**
      * Creates an expression tree enumerator.
      *
      * @param db database used by this enumerator
-     * @param evaluator
+     * @param evaluatorBuilder
      */
     public ExpressionCursorBuilder(BTreePartition db, AttributeTypeRegistry attributeTypeRegistry,
-        ExpressionEvaluator evaluator)
+        ExpressionEvaluatorBuilder evaluatorBuilder )
     {
         this.db = db;
-        this.evaluator = evaluator;
+        this.evaluatorBuilder = evaluatorBuilder;
 
-        LeafEvaluator leafEvaluator = evaluator.getLeafEvaluator();
+        LeafEvaluator leafEvaluator = evaluatorBuilder.getLeafEvaluator();
         scopeEnumerator = new ScopeCursorBuilder( db, leafEvaluator.getScopeEvaluator() );
         substringEnumerator = new SubstringCursorBuilder( db, attributeTypeRegistry, leafEvaluator.getSubstringEvaluator() );
     }
@@ -217,7 +217,7 @@
                 // NOTICE THE ! HERE
                 // The candidate is valid if it does not pass assertion. A
                 // candidate that passes assertion is therefore invalid.
-                return !evaluator.evaluate( node.getFirstChild(), rec );
+                return !evaluatorBuilder.evaluate( node.getFirstChild(), rec );
             }
         };
 
@@ -272,7 +272,7 @@
                     {
                         continue;
                     }
-                    else if ( !evaluator.evaluate( child, rec ) )
+                    else if ( !evaluatorBuilder.evaluate( child, rec ) )
                     {
                         return false;
                     }
@@ -396,7 +396,7 @@
         {
             public boolean assertCandidate( IndexEntry entry ) throws NamingException
             {
-                return evaluator.getLeafEvaluator().evaluate( node, entry );
+                return evaluatorBuilder.getLeafEvaluator().evaluate( node, entry );
             }
         };
 

Copied: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java (from r640704, directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluator.java)
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java?p2=directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java&p1=directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluator.java&r1=640704&r2=642020&rev=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluator.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java Thu Mar 27 16:13:30 2008
@@ -37,7 +37,7 @@
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public class ExpressionEvaluator implements Evaluator
+public class ExpressionEvaluatorBuilder implements EvaluatorBuilder
 {
     /** Leaf Evaluator flyweight use for leaf filter assertions */
     private LeafEvaluator leafEvaluator;
@@ -53,7 +53,7 @@
      *
      * @param leafEvaluator handles leaf node evaluation.
      */
-    public ExpressionEvaluator(LeafEvaluator leafEvaluator)
+    public ExpressionEvaluatorBuilder(LeafEvaluator leafEvaluator)
     {
         this.leafEvaluator = leafEvaluator;
     }
@@ -67,7 +67,7 @@
      * @param oidRegistry the oid reg used for attrID to oid resolution
      * @param attributeTypeRegistry the attribtype reg used for value comparison
      */
-    public ExpressionEvaluator(BTreePartition db, Registries registries )
+    public ExpressionEvaluatorBuilder(BTreePartition db, Registries registries )
     {
         ScopeEvaluator scopeEvaluator = null;
         SubstringEvaluator substringEvaluator = null;

Propchange: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/ExpressionEvaluatorBuilder.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar 27 16:13:30 2008
@@ -0,0 +1,4 @@
+Rev
+Revision
+Date
+Id

Modified: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/LeafEvaluator.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/LeafEvaluator.java?rev=642020&r1=642019&r2=642020&view=diff
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/LeafEvaluator.java (original)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/LeafEvaluator.java Thu Mar 27 16:13:30 2008
@@ -23,25 +23,16 @@
 import java.util.Comparator;
 import java.util.Iterator;
 
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
+import javax.naming.NamingEnumeration;
 
 import org.apache.directory.server.schema.registries.Registries;
 import org.apache.directory.server.xdbm.Index;
 import org.apache.directory.server.xdbm.IndexEntry;
+import org.apache.directory.server.xdbm.Store;
 import org.apache.directory.shared.ldap.NotImplementedException;
-import org.apache.directory.shared.ldap.filter.ApproximateNode;
-import org.apache.directory.shared.ldap.filter.EqualityNode;
-import org.apache.directory.shared.ldap.filter.ExprNode;
-import org.apache.directory.shared.ldap.filter.ExtensibleNode;
-import org.apache.directory.shared.ldap.filter.GreaterEqNode;
-import org.apache.directory.shared.ldap.filter.LessEqNode;
-import org.apache.directory.shared.ldap.filter.PresenceNode;
-import org.apache.directory.shared.ldap.filter.ScopeNode;
-import org.apache.directory.shared.ldap.filter.SimpleNode;
-import org.apache.directory.shared.ldap.filter.SubstringNode;
+import org.apache.directory.shared.ldap.filter.*;
 import org.apache.directory.shared.ldap.schema.AttributeType;
 import org.apache.directory.shared.ldap.schema.ByteArrayComparator;
 import org.apache.directory.shared.ldap.schema.MatchingRule;
@@ -56,7 +47,7 @@
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public class LeafEvaluator implements Evaluator
+public class LeafEvaluator implements Evaluator<Attributes>
 {
     /** equality matching type constant */
     private static final int EQUALITY_MATCH = 0;
@@ -68,29 +59,26 @@
     private static final int SUBSTRING_MATCH = 2;
 
     /** Database used to evaluate leaf with */
-    private BTreePartition db;
+    private final Store db;
 
     /** Oid Registry used to translate attributeIds to OIDs */
-    private Registries registries;
+    private final Registries registries;
 
     /** Substring node evaluator we depend on */
-    private SubstringEvaluator substringEvaluator;
+    private final SubstringEvaluator substringEvaluator;
 
     /** ScopeNode evaluator we depend on */
-    private ScopeEvaluator scopeEvaluator;
+    private final ScopeEvaluator scopeEvaluator;
 
+    /** The LeafNode this expression evaluator evaluates on candidates */
+    private final ExprNode expression;
 
-    /**
-     * Creates a leaf expression node evaluator.
-     *
-     * @param db
-     * @param scopeEvaluator
-     * @param substringEvaluator
-     */
-    public LeafEvaluator( BTreePartition db, Registries registries,
+
+    public LeafEvaluator( Store db, Registries registries, ExprNode expression,
         ScopeEvaluator scopeEvaluator, SubstringEvaluator substringEvaluator )
     {
         this.db = db;
+        this.expression = expression;
         this.registries = registries;
         this.scopeEvaluator = scopeEvaluator;
         this.substringEvaluator = substringEvaluator;
@@ -112,16 +100,9 @@
     /**
      * Match a filter value against an entry's attribute. An entry's attribute
      * may have more than one value, and the values may not be normalized. 
-     * @param node
-     * @param attr
-     * @param type
-     * @param normalizer
-     * @param comparator
-     * @return
-     * @throws NamingException
      */
     private boolean matchValue( SimpleNode node, Attribute attr, AttributeType type, Normalizer normalizer,
-        Comparator<Object> comparator ) throws NamingException
+        Comparator<Object> comparator ) throws Exception
     {
         // get the normalized AVA filter value
         Object filterValue = node.getValue();
@@ -161,7 +142,7 @@
     /**
      * Get the entry from the backend, if it's not already into the record
      */
-    private Attributes getEntry( IndexEntry rec ) throws NamingException
+    private Attributes getEntry( IndexEntry<?,Attributes> rec ) throws Exception
     {
         // get the attributes associated with the entry 
         Attributes entry = rec.getObject();
@@ -171,7 +152,7 @@
         // How possibly can't we have the entry at this point ?
         if ( null == entry )
         {
-            rec.setObject( db.lookup( ( Long ) rec.getId() ) );
+            rec.setObject( db.lookup( rec.getId() ) );
             entry = rec.getObject();
         }
 
@@ -180,11 +161,11 @@
 
 
     /**
-     * @see Evaluator#evaluate(ExprNode, IndexEntry)
+     * @see Evaluator#evaluate(IndexEntry)
      */
-    public boolean evaluate( ExprNode node, IndexEntry entry ) throws NamingException
+    public boolean evaluate( IndexEntry entry ) throws Exception
     {
-        if ( node instanceof ScopeNode )
+        if ( expression instanceof ScopeNode )
         {
             return scopeEvaluator.evaluate( node, entry );
         }
@@ -234,10 +215,10 @@
      * @param isGreaterOrLesser true if it is a greater than or equal to comparison,
      *      false if it is a less than or equal to comparison.
      * @return the ava evaluation on the perspective candidate
-     * @throws NamingException if there is a database access failure
+     * @throws Exception if there is a database access failure
      */
     private boolean evalGreaterOrLesser( SimpleNode node, IndexEntry entry, boolean isGreaterOrLesser )
-        throws NamingException
+        throws Exception
     {
         String attrId = node.getAttribute();
         long id = ( Long ) entry.getId();
@@ -574,9 +555,9 @@
      *
      * @param attrId the attribute identifier
      * @return the normalizer for equality matching
-     * @throws NamingException if there is a failure
+     * @throws Exception if there is a failure
      */
-    private Normalizer getNormalizer( String attrId, int matchType ) throws NamingException
+    private Normalizer getNormalizer( String attrId, int matchType ) throws Exception
     {
         MatchingRule mrule = getMatchingRule( attrId, matchType );
 
@@ -594,9 +575,9 @@
      *
      * @param attrId the attribute identifier
      * @return the matching rule
-     * @throws NamingException if there is a failure
+     * @throws Exception if there is a failure
      */
-    private MatchingRule getMatchingRule( String attrId, int matchType ) throws NamingException
+    private MatchingRule getMatchingRule( String attrId, int matchType ) throws Exception
     {
         MatchingRule mrule = null;
         String oid = registries.getOidRegistry().getOid( attrId );

Added: directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/OrCursor.java
URL: http://svn.apache.org/viewvc/directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/OrCursor.java?rev=642020&view=auto
==============================================================================
--- directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/OrCursor.java (added)
+++ directory/sandbox/akarasulu/bigbang/apacheds/xdbm-search/src/main/java/org/apache/directory/server/xdbm/search/impl/OrCursor.java Thu Mar 27 16:13:30 2008
@@ -0,0 +1,238 @@
+/*
+ *  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. 
+ *  
+ */
+package org.apache.directory.server.xdbm.search.impl;
+
+
+import org.apache.directory.server.core.cursor.Cursor;
+import org.apache.directory.server.core.cursor.AbstractCursor;
+import org.apache.directory.server.core.cursor.CursorIterator;
+import org.apache.directory.server.xdbm.IndexEntry;
+
+import java.util.*;
+
+
+/**
+ * An OR'ing Cursor intended for returning large result sets.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $$Rev$$
+ */
+public class OrCursor<E> extends AbstractCursor<IndexEntry<?,E>>
+{
+    private static final String UNSUPPORTED_MSG =
+        "DisjunctionCursors are not ordered and do not support positioning by element.";
+    private final Cursor<IndexEntry<?,E>>[] cursors;
+    private final Evaluator[] evaluators;
+    private final List<Set<Long>> blacklists;
+    private int cursorIndex = -1;
+    private boolean available = false;
+
+
+    public OrCursor( Cursor<IndexEntry<?,E>>[] cursors, Evaluator[] evaluators )
+    {
+        if ( cursors.length <= 1 )
+        {
+            throw new IllegalArgumentException(
+                "Must have 2 or more sub-expression Cursors for a disjunction" );
+        }
+
+        this.cursors = cursors;
+        this.evaluators = evaluators;
+        this.blacklists = new ArrayList<Set<Long>>();
+        //noinspection ForLoopReplaceableByForEach
+        for ( int ii = 0; ii < cursors.length; ii++ )
+        {
+            this.blacklists.add( new HashSet<Long>() );
+        }
+    }
+
+
+    public boolean available()
+    {
+        return available;
+    }
+
+
+    public void before( IndexEntry<?, E> element ) throws Exception
+    {
+        throw new UnsupportedOperationException( UNSUPPORTED_MSG );
+    }
+
+
+    public void after( IndexEntry<?, E> element ) throws Exception
+    {
+        throw new UnsupportedOperationException( UNSUPPORTED_MSG );
+    }
+
+
+    public void beforeFirst() throws Exception
+    {
+        cursorIndex = 0;
+        cursors[cursorIndex].beforeFirst();
+    }
+
+
+    public void afterLast() throws Exception
+    {
+        cursorIndex = cursors.length - 1;
+        cursors[cursorIndex].afterLast();
+    }
+
+
+    public boolean first() throws Exception
+    {
+        beforeFirst();
+        return available = next();
+    }
+
+
+    public boolean last() throws Exception
+    {
+        afterLast();
+        return available = previous();
+    }
+
+
+    private boolean isBlackListed( Long id )
+    {
+        return blacklists.get( cursorIndex ).contains( id );
+    }
+
+
+    /**
+     * The first sub-expression Cursor to advance to an entry adds the entry
+     * to the blacklists of other Cursors that might return that entry.
+     *
+     * @param indexEntry the index entry to blacklist
+     * @throws Exception if there are problems accessing underlying db
+     */
+    private void blackListIfDuplicate( IndexEntry<?,E> indexEntry ) throws Exception
+    {
+        for ( int ii = 0; ii < evaluators.length; ii++ )
+        {
+            if ( ii == cursorIndex )
+            {
+                continue;
+            }
+
+            if ( evaluators[ii].evaluate( indexEntry ) )
+            {
+                blacklists.get( ii ).add( indexEntry.getId() );
+            }
+        }
+    }
+
+
+    public boolean previous() throws Exception
+    {
+        while ( cursors[cursorIndex].previous() )
+        {
+            IndexEntry<?,E> candidate = cursors[cursorIndex].get();
+            if ( ! isBlackListed( candidate.getId() ) )
+            {
+                blackListIfDuplicate( candidate );
+                return available = true;
+            }
+        }
+
+        while ( cursorIndex > 0 )
+        {
+            cursorIndex--;
+            cursors[cursorIndex].afterLast();
+
+            while ( cursors[cursorIndex].previous() )
+            {
+                IndexEntry<?,E> candidate = cursors[cursorIndex].get();
+                if ( ! isBlackListed( candidate.getId() ) )
+                {
+                    blackListIfDuplicate( candidate );
+                    return available = true;
+                }
+            }
+        }
+
+        return available = false;
+    }
+
+
+    public boolean next() throws Exception
+    {
+        while ( cursors[cursorIndex].next() )
+        {
+            IndexEntry<?,E> candidate = cursors[cursorIndex].get();
+            if ( ! isBlackListed( candidate.getId() ) )
+            {
+                blackListIfDuplicate( candidate );
+                return available = true;
+            }
+        }
+
+        while ( cursorIndex < cursors.length - 1 )
+        {
+            cursorIndex++;
+            cursors[cursorIndex].beforeFirst();
+
+            while ( cursors[cursorIndex].next() )
+            {
+                IndexEntry<?,E> candidate = cursors[cursorIndex].get();
+                if ( ! isBlackListed( candidate.getId() ) )
+                {
+                    blackListIfDuplicate( candidate );
+                    return available = true;
+                }
+            }
+        }
+
+        return available = false;
+    }
+
+
+    public IndexEntry<?, E> get() throws Exception
+    {
+        if ( available )
+        {
+            return cursors[cursorIndex].get();
+        }
+
+        throw new InvalidPropertiesFormatException( "Cursor has not been positioned." );
+    }
+
+
+    public boolean isElementReused()
+    {
+        return cursors[cursorIndex].isElementReused();
+    }
+
+
+    public Iterator<IndexEntry<?, E>> iterator()
+    {
+        return new CursorIterator<IndexEntry<?, E>>( this );
+    }
+
+
+    public void close() throws Exception
+    {
+        for ( Cursor cursor : cursors )
+        {
+            cursor.close();
+        }
+        super.close();
+    }
+}
\ No newline at end of file