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