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 2004/09/30 06:35:02 UTC

svn commit: rev 47553 - incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db

Author: akarasulu
Date: Wed Sep 29 21:35:00 2004
New Revision: 47553

Removed:
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/DatabaseEnabled.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorDependent.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/LeafEvaluatorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/NegationEnumeratorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEnumeratorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEvaluatorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEnumeratorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEvaluatorImpl.java
Modified:
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ConjunctionEnumerator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/DupsEnumeration.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorImpl.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorMonitorAdapter.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/LeafEvaluator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/NegationEnumerator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEnumerator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEvaluator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEnumerator.java
   incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEvaluator.java
Log:
Removed a bunch of do nothing interfaces that extended Evaluator and Enumerator
and renamed the Impl class to the old name of the deleted interface.


Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ConjunctionEnumerator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ConjunctionEnumerator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ConjunctionEnumerator.java	Wed Sep 29 21:35:00 2004
@@ -1,3 +1,19 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
 package org.apache.eve.db;
 
 
@@ -15,6 +31,8 @@
  * An enumerator implementation which creates a NamingEnumeration over the
  * candidates satisfying a filter expression of AND'ed filter sub-expressions.
  * 
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
  */
 public class ConjunctionEnumerator implements Enumerator
 {

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/DupsEnumeration.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/DupsEnumeration.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/DupsEnumeration.java	Wed Sep 29 21:35:00 2004
@@ -38,8 +38,7 @@
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public class DupsEnumeration
-    implements NamingEnumeration
+public class DupsEnumeration implements NamingEnumeration
 {
     /** Marker for whether or not next() will return successfully */
     private boolean hasMore = true;

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorImpl.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorImpl.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorImpl.java	Wed Sep 29 21:35:00 2004
@@ -59,11 +59,11 @@
                            LeafEvaluator leafEvaluator )
     {
         this.db = db;
-        scopeEnumerator = new ScopeEnumeratorImpl();
-        substringEnumerator = new SubstringEnumeratorImpl();
+        scopeEnumerator = new ScopeEnumerator();
+        substringEnumerator = new SubstringEnumerator();
         conjunctionEnumerator = new ConjunctionEnumerator( this, topEvaluator );
         disjunctionEnumerator = new DisjunctionEnumerator( this );
-        negationEnumerator = new NegationEnumeratorImpl();
+        negationEnumerator = new NegationEnumerator();
     }
 
 

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorMonitorAdapter.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorMonitorAdapter.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/EnumeratorMonitorAdapter.java	Wed Sep 29 21:35:00 2004
@@ -19,8 +19,7 @@
 /**
  * Document me.
  *
- * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory
- *         Project</a>
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
 public class EnumeratorMonitorAdapter implements EnumeratorMonitor

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/LeafEvaluator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/LeafEvaluator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/LeafEvaluator.java	Wed Sep 29 21:35:00 2004
@@ -17,12 +17,291 @@
 package org.apache.eve.db;
 
 
+import java.math.BigInteger;
+import java.util.Comparator;
+
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.LeafNode;
+import org.apache.ldap.common.filter.ScopeNode;
+import org.apache.ldap.common.filter.SimpleNode;
+import org.apache.ldap.common.schema.Normalizer;
+import org.apache.ldap.common.filter.PresenceNode;
+import org.apache.ldap.common.NotImplementedException;
+
+import org.apache.eve.schema.NormalizerRegistry;
+import org.apache.eve.schema.ComparatorRegistry;
+
+
 /**
- * Interface for leaf node evaluation. 
+ * Evaluates LeafNode assertions on candidates using a database.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface LeafEvaluator extends Evaluator
+public class LeafEvaluator implements Evaluator
 {
-}
\ No newline at end of file
+    /** Database used to evaluate leaf with */
+    private Database db;
+    /** Normalizer registry for up value normalization */
+    private NormalizerRegistry normalizerRegistry;
+    /** Comparator registry for comparing normalized values */
+    private ComparatorRegistry comparatorRegistry;
+    /** Substring node evaluator we depend on */
+    private SubstringEvaluator substringEvaluator;
+    /** ScopeNode evaluator we depend on */
+    private ScopeEvaluator scopeEvaluator;
+
+
+
+    public LeafEvaluator( Database db,
+                              ScopeEvaluator scopeEvaluator,
+                              NormalizerRegistry normalizerRegistry,
+                              ComparatorRegistry comparatorRegistry,
+                              SubstringEvaluator substringEvaluator )
+    {
+        this.db = db;
+        this.scopeEvaluator = scopeEvaluator;
+        this.normalizerRegistry = normalizerRegistry;
+        this.comparatorRegistry = comparatorRegistry;
+        this.substringEvaluator = substringEvaluator;
+    }
+
+
+    /**
+     * @see org.apache.eve.db.Evaluator#evaluate(ExprNode, IndexRecord)
+     */
+    public boolean evaluate( ExprNode node, IndexRecord record )
+        throws NamingException
+    {
+        if ( node instanceof ScopeNode )
+        {
+            return scopeEvaluator.evaluate( node, record );
+        }
+        
+        switch( ( ( LeafNode ) node ).getAssertionType() ) 
+        {
+        case( LeafNode.APPROXIMATE ):
+            return evalEquality( ( SimpleNode ) node, record );
+        case( LeafNode.EQUALITY ):
+            return evalEquality( ( SimpleNode ) node, record );
+        case( LeafNode.EXTENSIBLE ):
+            throw new NotImplementedException();
+        case( LeafNode.GREATEREQ ):
+            return evalGreater( ( SimpleNode ) node, record, true );
+        case( LeafNode.LESSEQ ):
+            return evalGreater( ( SimpleNode ) node, record, false );
+        case( LeafNode.PRESENCE ):
+            String attrId = ( ( PresenceNode ) node ).getAttribute();
+            return evalPresence( attrId, record ); 
+        case( LeafNode.SUBSTRING ):
+            return substringEvaluator.evaluate( node, record );
+        default:
+            throw new NamingException( "Unrecognized leaf node type: "
+                + ( ( LeafNode ) node ).getAssertionType() );
+        }
+    }
+    
+    
+    /**
+     * Evaluates a simple greater than or less than attribute value assertion on
+     * a perspective candidate.
+     * 
+     * @param node the greater than or less than node to evaluate
+     * @param record the IndexRecord of the perspective candidate
+     * @param isGreater 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
+     */
+    private boolean evalGreater( SimpleNode node, IndexRecord record,
+        boolean isGreater ) throws NamingException
+    {
+        String attrId = node.getAttribute();
+        BigInteger id = record.getEntryId();
+        
+        if ( db.hasUserIndexOn( attrId ) )
+        {
+            Index idx = db.getUserIndex( attrId );
+            
+            if ( isGreater )
+            {
+                return idx.hasValue( node.getValue(), id, true ); 
+            }
+            
+            return idx.hasValue( node.getValue(), id, false );
+        }
+        
+        // resusitate entry if need be
+        if ( null == record.getAttributes() )
+        {
+            record.setAttributes( db.lookup( id ) );
+        }
+        
+        // get the attribute associated with the node 
+        Attribute attr = record.getAttributes().get( attrId );
+
+        // If we do not have the attribute just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+        
+        /*
+         * We need to iterate through all values and for each value we normalize
+         * and use the comparator to determine if a match exists.
+         */
+        Normalizer normalizer = normalizerRegistry.getEquality( attrId );
+        Comparator comparator = comparatorRegistry.getEquality( attrId );
+        Object filterValue = normalizer.normalize( node.getValue() );
+        NamingEnumeration list = attr.getAll();
+        
+        /*
+         * Cheaper to not check isGreater in one loop - better to separate
+         * out into two loops which you choose to execute based on isGreater
+         */
+        if ( isGreater )
+        {
+            while ( list.hasMore() )
+            {
+                Object value = normalizer.normalize( list.next() );
+            
+                // Found a value that is greater than or equal to the ava value
+                if ( 0 >= comparator.compare( value, filterValue ) )
+                {
+                    return true;
+                }
+            }
+        }
+        else 
+        {    
+            while ( list.hasMore() )
+            {
+                Object value = normalizer.normalize( list.next() );
+            
+                // Found a value that is less than or equal to the ava value
+                if ( 0 <= comparator.compare( value, filterValue ) )
+                {
+                    return true;
+                }
+            }
+        }
+        
+        // no match so return false
+        return false;
+    }
+
+    
+    /**
+     * Evaluates a simple presence attribute value assertion on a perspective
+     * candidate.
+     * 
+     * @param attrId the name of the attribute tested for presence 
+     * @param rec the IndexRecord of the perspective candidate
+     * @return the ava evaluation on the perspective candidate
+     * @throws NamingException if there is a database access failure
+     */
+    private boolean evalPresence( String attrId, IndexRecord rec ) 
+        throws NamingException
+    {
+        if ( db.hasUserIndexOn( attrId ) )
+        {
+            Index idx = db.getExistanceIndex();
+            return idx.hasValue( attrId, rec.getEntryId() );
+        }
+        
+        // resusitate entry if need be
+        if ( null == rec.getAttributes() )
+        {
+            rec.setAttributes( db.lookup( rec.getEntryId() ) );
+        }
+        
+        // get the attribute associated with the node 
+        Attributes attrs = rec.getAttributes();
+        return null != attrs.get( attrId );
+    }
+    
+
+    /**
+     * Evaluates a simple equality attribute value assertion on a perspective
+     * candidate.
+     * 
+     * @param node the equality node to evaluate 
+     * @param rec the IndexRecord of the perspective candidate
+     * @return the ava evaluation on the perspective candidate
+     * @throws NamingException if there is a database access failure
+     */
+    private boolean evalEquality( SimpleNode node, IndexRecord rec )
+        throws NamingException
+    {
+        if ( db.hasUserIndexOn( node.getAttribute() ) )
+        {
+            Index idx = db.getUserIndex( node.getAttribute() );
+            return idx.hasValue( node.getValue(), rec.getEntryId() );
+        }
+
+        Normalizer normalizer = normalizerRegistry.getEquality( node.getAttribute() );
+        Comparator comparator = comparatorRegistry.getEquality( node.getAttribute() );
+
+        /*
+         * Get the attribute and if it is not set in rec then resusitate it
+         * from the master table and set it in rec for use later if at all.
+         * Before iterating through all values for a match check to see if the
+         * AVA value is contained or the normalized form of the AVA value is 
+         * contained.
+         */
+        
+        // resusitate entry if need be
+        if ( null == rec.getAttributes() )
+        {
+            rec.setAttributes( db.lookup( rec.getEntryId() ) );
+        }
+        
+        // get the attribute associated with the node 
+        Attribute attr = rec.getAttributes().get( node.getAttribute() );
+        
+        // If we do not have the attribute just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+        
+        // check if AVA value exists in attribute
+        if ( attr.contains( node.getValue() ) )
+        {
+            return true;
+        }
+
+        // get the normalized AVA filter value
+        Object filterValue = normalizer.normalize( node.getValue() );
+
+        // check if the normalized value is present
+        if ( attr.contains( filterValue ) )
+        {
+            return true;
+        }
+        
+        /*
+         * We need to now iterate through all values because we could not get
+         * a lookup to work.  For each value we normalize and use the comparator
+         * to determine if a match exists.
+         */
+        NamingEnumeration list = attr.getAll();
+        while ( list.hasMore() )
+        {
+            Object value = normalizer.normalize( list.next() );
+            
+            if ( 0 == comparator.compare( value, filterValue ) )
+            {
+                return true;
+            }
+        }
+        
+        // no match so return false
+        return false;
+    }
+}

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/NegationEnumerator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/NegationEnumerator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/NegationEnumerator.java	Wed Sep 29 21:35:00 2004
@@ -17,13 +17,79 @@
 package org.apache.eve.db;
 
 
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.LeafNode;
+import org.apache.ldap.common.filter.BranchNode;
+
+
 /**
- * Creates Enumerations over a set of entry candidates based on a negated 
- * expression.
+ * Creates a naming enumeration over the set of candidates accepted by a negated
+ * filter expression. 
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface NegationEnumerator extends Enumerator
+public class NegationEnumerator implements Enumerator
 {
+    /** Database this conjunction is applied upon */
+    private Database db = null;
+    /** Top level expression evaluator */
+    private Evaluator evaluator;
+
+
+    /**
+     * Creates a negation branch node enumerator.
+     *
+     * @param db the database to use for enumerations
+     * @param evaluator the top level evaluator
+     */
+    public NegationEnumerator( Database db, Evaluator evaluator )
+    {
+        this.db = db;
+        this.evaluator = evaluator;
+    }
+
+
+    /**
+     * @see Enumerator#enumerate(ExprNode)
+     */
+    public NamingEnumeration enumerate( ExprNode node ) throws NamingException
+    {
+        Index idx = null;
+        final BranchNode bnode = ( BranchNode ) node;
+        NamingEnumeration childEnumeration = null;
+        NamingEnumeration enumeration = null;
+
+        // Iterates over entire set of index values
+        if ( bnode.getChild().isLeaf() )
+        {
+            LeafNode child = ( LeafNode ) bnode.getChild();
+            idx = db.getUserIndex( child.getAttribute() );
+            childEnumeration = idx.listIndices();
+        } 
+        // Iterates over the entire set of entries
+        else 
+        {
+            idx = db.getNdnIndex();
+            childEnumeration = idx.listIndices();
+        }
+
+
+        IndexAssertion assertion = new IndexAssertion()
+        {
+            public boolean assertCandidate( IndexRecord rec ) throws NamingException
+            {
+                // NOTICE THE ! HERE
+                // The candidate is valid if it does not pass assertion. A
+                // candidate that passes assertion is therefore invalid.
+                return ! evaluator.evaluate( bnode.getChild(), rec );
+            }
+        };
+
+        enumeration = new IndexAssertionEnumeration( childEnumeration, assertion, true );
+        return enumeration;
+    }
 }

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEnumerator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEnumerator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEnumerator.java	Wed Sep 29 21:35:00 2004
@@ -17,12 +17,221 @@
 package org.apache.eve.db;
 
 
+import java.math.BigInteger;
+
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.SearchControls;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.ScopeNode;
+import org.apache.ldap.common.util.SingletonEnumeration;
+
+
 /**
- * Creates Enumerations over a set of entry candidates based on scope.
+ * Enumerates candidates based on scope.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface ScopeEnumerator extends Enumerator
+public class ScopeEnumerator implements Enumerator
 {
+    /** Database used to enumerate based on scope */
+    private Database db = null;
+    /** Filter scope expression evaluator */
+    private ScopeEvaluator evaluator = null;
+
+
+    public ScopeEnumerator( Database db, ScopeEvaluator evaluator )
+    {
+        this.db = db;
+        this.evaluator = evaluator;
+    }
+
+
+    /**
+     * Builds an enumeration over all entries that satisfy the constraints of 
+     * the scope assertion node.
+     *
+     * @param node the scope node 
+     * @return the candidates that are within scope
+     * @throws NamingException if any system indices fail
+     * @see Enumerator#enumerate(ExprNode)
+     */
+    public NamingEnumeration enumerate( ExprNode node ) throws NamingException
+    {
+        final ScopeNode snode = ( ScopeNode ) node;
+        final BigInteger id = db.getEntryId( snode.getBaseDn() );
+
+        switch( snode.getScope() )
+        {
+        case( SearchControls.OBJECT_SCOPE ):
+            final IndexRecord record = new IndexRecord();
+            record.setEntryId( id );
+            record.setIndexKey( snode.getBaseDn() );
+            return new SingletonEnumeration( record ); 
+        case( SearchControls.ONELEVEL_SCOPE ):
+            return enumerateChildren( snode.getBaseDn(),
+                snode.getDerefAliases().derefInSearching() );
+        case( SearchControls.SUBTREE_SCOPE ):
+            return enumerateDescendants( snode );
+        default:
+            throw new NamingException( "Unrecognized search scope!" );
+        }
+    }
+
+
+    /**
+     * Constructs an enumeration over all entries within one level scope even
+     * when aliases are enabled while searching.
+     * 
+     * @param dn the base dn
+     * @param deref whether or not we dereference while searching
+     * @return the enumeration of all entries in direct or alias extended one 
+     * level scope to the base
+     * @throws NamingException if any failures occur while accessing system
+     * indices.
+     */
+    private NamingEnumeration enumerateChildren( String dn, boolean deref )
+        throws NamingException
+    {
+        Index idx = db.getHeirarchyIndex();
+        final BigInteger id = db.getEntryId( dn );
+        final NamingEnumeration children = idx.listIndices( id );
+        
+        /*
+         * If alias dereferencing is not enabled while searching then we just
+         * return the enumeration of the base entry's children.
+         */
+        if ( ! deref )
+        {
+           return children; 
+        }
+
+        /* ====================================================================
+         * From here on Dereferencing while searching is enabled
+         * ====================================================================
+         *
+         * Dereferencing in search is enabled so we need to wrap the child
+         * listing with an assertion enumeration to weed out aliases that will
+         * not be returned.  Next we need to compose an enumeration which 
+         * combines the list of non-alias child entries with those entries that
+         * are brought into one level scope by aliases.
+         */
+
+        // List all entries brought into one level scope at base by aliases
+        idx = db.getOneAliasIndex();
+        NamingEnumeration aliasIntroduced = idx.listIndices( id );
+        
+        // Still need to use assertion enum to weed out aliases
+        NamingEnumeration nonAliasChildren = new IndexAssertionEnumeration( 
+            children, new AssertNotAlias() );
+        
+        // Combine both into one enumeration
+        NamingEnumeration [] all = {nonAliasChildren, aliasIntroduced}; 
+        return new DisjunctionEnumeration( all );
+    }
+    
+
+    /**
+     * Constructs an enumeration over all entries within subtree scope even
+     * when aliases are enabled while searching.
+     * 
+     * @param node the scope node
+     * @return the enumeration of all entries in direct or alias extended 
+     * subtree scope to the base
+     * @throws NamingException if any failures occur while accessing system
+     * indices.
+     */
+    private NamingEnumeration enumerateDescendants( final ScopeNode node )
+        throws NamingException
+    {
+        Index idx = null;
+
+        /*
+         * If we do not dereference while searching then we simply return any
+         * entry that is not a descendant of the base.
+         */
+        if ( ! node.getDerefAliases().derefInSearching() )
+        {
+            // Gets a NamingEnumeration over all elements
+            idx = db.getNdnIndex();
+            NamingEnumeration underlying = idx.listIndices();
+            return new IndexAssertionEnumeration( underlying, 
+                new AssertDescendant( node ) );
+        }
+
+        // Create an assertion to assert or evaluate an expression
+        IndexAssertion assertion = new IndexAssertion()
+        {
+            public boolean assertCandidate( IndexRecord rec )
+                throws NamingException
+            {
+                return evaluator.evaluate( node, rec );
+            }
+        };
+
+        // Gets a NamingEnumeration over all elements
+        idx = db.getNdnIndex();
+        NamingEnumeration underlying = idx.listIndices();
+        return new IndexAssertionEnumeration( underlying, assertion );
+    }
+
+
+    /**
+     * Asserts an entry is a descendant.
+     */
+    class AssertDescendant implements IndexAssertion
+    {
+        /** Scope node with base and alias info */
+        private final ScopeNode scope;
+
+        
+        /**
+         * Creates a assertion using a ScopeNode to determine the search base.
+         *
+         * @param node the scope node with search base
+         */
+        AssertDescendant( final ScopeNode node )
+        {
+            scope = node;
+        }
+
+
+        /**
+         * Returns true if the candidate with id is a descendant of the base, 
+         * false otherwise.
+         * 
+         * @see IndexAssertion#assertCandidate(IndexRecord)
+         */
+        public boolean assertCandidate( IndexRecord record ) throws NamingException
+        {
+            String dn = db.getEntryDn( record.getEntryId() );
+            return dn.endsWith( scope.getBaseDn() );
+        }
+    }    
+
+
+    /**
+     * Asserts an entry is NOT an alias.
+     */
+    class AssertNotAlias implements IndexAssertion
+    {
+        /**
+         * Returns true if the candidate is not an alias, false otherwise.
+         * 
+         * @see IndexAssertion#assertCandidate(IndexRecord)
+         */
+        public boolean assertCandidate( IndexRecord record ) throws NamingException
+        {
+            Index aliasIdx = db.getAliasIndex();
+               
+            if ( null == aliasIdx.reverseLookup( record.getEntryId() ) )
+            {
+                return true;
+            }
+               
+            return false;
+        } 
+    }
 }

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEvaluator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEvaluator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/ScopeEvaluator.java	Wed Sep 29 21:35:00 2004
@@ -1,5 +1,193 @@
 /*
- *   Copyright 2004 The Apache Software Foundation
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
  *   you may not use this file except in compliance with the License.
@@ -14,15 +202,200 @@
  *   limitations under the License.
  *
  */
+
+/*
+ * $Id: ScopeEvaluator.java,v 1.3 2003/10/15 01:59:46 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group                                                    --
+ * -- Please refer to the LICENSE.txt file in the root directory of      --
+ * -- any LDAPd project for copyright and distribution information.      --
+ *
+ * Created on Oct 9, 2003
+ */
 package org.apache.eve.db;
 
 
+import java.math.BigInteger;
+
+import javax.naming.NamingException;
+import javax.naming.directory.SearchControls;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.ScopeNode;
+import org.apache.ldap.common.message.DerefAliasesEnum;
+
+
 /**
- * Evaluator interface for handling scope node evaluations.
+ * Evaluates ScopeNode assertions on candidates using a database.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface ScopeEvaluator extends Evaluator
+public class ScopeEvaluator implements Evaluator
 {
-}
\ No newline at end of file
+    /** Database used to evaluate scope with */
+    private Database db;
+
+
+    /**
+     * Creates a scope node evaluator for search expressions.
+     *
+     * @param db the database used to evaluate scope node
+     */
+    public ScopeEvaluator( Database db )
+    {
+        this.db = db;
+    }
+
+
+    /**
+     * @see org.apache.eve.db.Evaluator#evaluate(ExprNode, IndexRecord)
+     */
+    public boolean evaluate( ExprNode node, IndexRecord record )
+        throws NamingException
+    {
+        ScopeNode snode = ( ScopeNode ) node;
+        
+        switch( snode.getScope() )
+        {
+        case( SearchControls.OBJECT_SCOPE ):
+            String dn = db.getEntryDn( record.getEntryId() );
+            return dn.equals( snode.getBaseDn() );
+        case( SearchControls.ONELEVEL_SCOPE ):
+            return assertOneLevelScope( snode, record.getEntryId() );
+        case( SearchControls.SUBTREE_SCOPE ):
+            return assertSubtreeScope( snode, record.getEntryId() );
+        default:
+            throw new NamingException( "Unrecognized search scope!" );
+        }
+    }
+    
+    
+    /**
+     * Asserts whether or not a candidate has one level scope while taking
+     * alias dereferencing into account.
+     * 
+     * @param node the scope node containing the base and alias handling mode
+     * @param id the candidate to assert which can be any db entry's id
+     * @return true if the candidate is within one level scope whether or not
+     * alias dereferencing is enabled.
+     * @throws NamingException if the index lookups fail.
+     */
+    public boolean assertSubtreeScope( final ScopeNode node, 
+        final BigInteger id ) throws NamingException
+    {
+        String dn = db.getEntryDn( id );
+        DerefAliasesEnum mode = node.getDerefAliases();
+        Object baseId = db.getEntryId( node.getBaseDn() );
+        boolean isDescendant = dn.endsWith( node.getBaseDn() );
+        
+        /*
+         * The candidate id could be any entry in the db.  If search 
+         * dereferencing is not enabled then we return the results of the 
+         * descendant test.
+         */
+        if ( ! mode.derefInSearching() )
+        {
+            return isDescendant;
+        }
+
+        /*
+         * From here down alias dereferencing is enabled.  We determine if the
+         * candidate id is an alias, if so we reject it since aliases should
+         * not be returned.
+         */
+        Index idx = db.getAliasIndex();
+        if ( null != idx.reverseLookup( id ) )
+        {
+            return false;
+        }
+        
+        /*
+         * The candidate is NOT an alias at this point.  So if it is a 
+         * descendant we just return it since it is in normal subtree scope.
+         */
+        if ( isDescendant )
+        {
+            return true;
+        }
+        
+        /*
+         * At this point the candidate is not a descendant and it is not an 
+         * alias.  We need to check if the candidate is in extended subtree 
+         * scope by performing a lookup on the subtree alias index.  This index 
+         * stores a tuple mapping the baseId to the ids of objects brought 
+         * into subtree scope of the base by an alias: 
+         * 
+         * ( baseId, aliasedObjId )
+         * 
+         * If the candidate id is an object brought into subtree scope then 
+         * the lookup returns true accepting the candidate.  Otherwise the 
+         * candidate is rejected with a false return because it is not in scope.
+         */
+        idx = db.getSubAliasIndex();
+        return idx.hasValue( baseId, id );
+    }
+    
+    
+    /**
+     * Asserts whether or not a candidate has one level scope while taking
+     * alias dereferencing into account.
+     * 
+     * @param node the scope node containing the base and alias handling mode
+     * @param id the candidate to assert which can be any db entry's id 
+     * @return true if the candidate is within one level scope whether or not
+     * alias dereferencing is enabled.
+     * @throws NamingException if the index lookups fail.
+     */
+    public boolean assertOneLevelScope( final ScopeNode node, 
+        final BigInteger id ) throws NamingException
+    {
+        DerefAliasesEnum mode = node.getDerefAliases();
+        Object baseId = db.getEntryId( node.getBaseDn() );
+        Index idx = db.getHeirarchyIndex();
+        boolean isChild = idx.hasValue( baseId, id );
+
+        /*
+         * The candidate id could be any entry in the db.  If search 
+         * dereferencing is not enabled then we return the results of the child 
+         * test. 
+         */
+        if ( ! mode.derefInSearching() )
+        {
+            return isChild;
+        }
+
+        /*
+         * From here down alias dereferencing is enabled.  We determine if the
+         * candidate id is an alias, if so we reject it since aliases should
+         * not be returned.
+         */
+        idx = db.getAliasIndex();
+        if ( null != idx.reverseLookup( id ) )
+        {
+            return false;
+        }
+        
+        /*
+         * The candidate is NOT an alias at this point.  So if it is a child we
+         * just return it since it is in normal one level scope.
+         */
+        if ( isChild )
+        {
+            return true;
+        }
+        
+        /*
+         * At this point the candidate is not a child and it is not an alias.
+         * We need to check if the candidate is in extended one level scope by 
+         * performing a lookup on the one level alias index.  This index stores
+         * a tuple mapping the baseId to the id of objects brought into the 
+         * one level scope of the base by an alias: ( baseId, aliasedObjId )
+         * If the candidate id is an object brought into one level scope then 
+         * the lookup returns true accepting the candidate.  Otherwise the 
+         * candidate is rejected with a false return because it is not in scope.
+         */
+        idx = db.getOneAliasIndex();
+        return idx.hasValue( baseId, id );
+    }
+}

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEnumerator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEnumerator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEnumerator.java	Wed Sep 29 21:35:00 2004
@@ -1,5 +1,193 @@
 /*
- *   Copyright 2004 The Apache Software Foundation
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
  *
  *   Licensed under the Apache License, Version 2.0 (the "License");
  *   you may not use this file except in compliance with the License.
@@ -14,16 +202,125 @@
  *   limitations under the License.
  *
  */
+
+/*
+ * $Id: SubstringEnumerator.java,v 1.2 2003/10/17 00:10:46 akarasulu Exp $
+ *
+ * -- (c) LDAPd Group                                                    --
+ * -- Please refer to the LICENSE.txt file in the root directory of      --
+ * -- any LDAPd project for copyright and distribution information.      --
+ *
+ * Created on Oct 13, 2003
+ */
 package org.apache.eve.db;
 
 
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.SubstringNode;
+
+
 /**
- * Creates Enumerations over a set of entry candidates based on a substring 
- * assertions.
+ * Enumerator that creates a NamingEnumeration over the set of candidates that 
+ * satisfy a substring filter expression.
  * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface SubstringEnumerator extends Enumerator
+public class SubstringEnumerator implements Enumerator
 {
-}
+    /** Database used */
+    private Database db = null;
+    /** Evaluator used is an Avalon dependent object */
+    private SubstringEvaluator evaluator = null;
+
+
+    /**
+     * Creates a SubstringEnumerator for a database.
+     *
+     * @param db the database
+     * @param evaluator a substring evaluator
+     */
+    public SubstringEnumerator( Database db, SubstringEvaluator evaluator )
+    {
+        this.db = db;
+        this.evaluator = evaluator;
+    }
+
+
+    // ------------------------------------------------------------------------
+    // SubstringEnumerator Methods
+    // ------------------------------------------------------------------------
+    
+    
+    /**
+     * @see Enumerator#enumerate(
+     * org.apache.ldap.common.filter.ExprNode)
+     */
+    public NamingEnumeration enumerate( final ExprNode node )
+        throws NamingException
+    {
+        RE regex = null;
+        Index idx = null;
+        final SubstringNode snode = ( SubstringNode ) node;
+    
+        if ( db.hasUserIndexOn( snode.getAttribute() ) )
+        {
+            /*
+             * Build out regex in this block so we do not do it twice in the
+             * evaluator if there is no index on the attribute of the substr ava
+             */
+            try 
+            {
+                regex = snode.getRegex();
+            } 
+            catch ( RESyntaxException e ) 
+            {
+                NamingException ne = new NamingException( "SubstringNode '" 
+                    + node + "' had incorrect syntax" );
+                ne.setRootCause( e );
+                throw ne;
+            }
+
+            /*
+             * Get the user index and return an index enumeration using the the
+             * compiled regular expression.  Try to constrain even further if
+             * an initial term is available in the substring expression.
+             */
+            idx = db.getUserIndex( snode.getAttribute() );
+            if ( null == snode.getInitial() )
+            {
+                return idx.listIndices( regex );
+            } 
+            else 
+            {
+                return idx.listIndices( regex, snode.getInitial() );
+            }
+        }
+        
+        /*
+         * From this point on we are dealing with an enumeration over entries
+         * based on an attribute that is not indexed.  We have no choice but
+         * to perform a full table scan but need to leverage an index for the
+         * underlying enumeration.  We know that all entries are listed under 
+         * the ndn index and so this will enumerate over all entries as the 
+         * underlying enumeration.  An evaluator in an assertion is used to 
+         * constrain the result set.
+         */
+        NamingEnumeration underlying = db.getNdnIndex().listIndices();
+        IndexAssertion assertion = new IndexAssertion()
+        {
+            public boolean assertCandidate( final IndexRecord record ) throws NamingException
+            {
+                return evaluator.evaluate( node, record );
+            }
+        };
+
+        return new IndexAssertionEnumeration( underlying, assertion );
+    }
+}
\ No newline at end of file

Modified: incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEvaluator.java
==============================================================================
--- incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEvaluator.java	(original)
+++ incubator/directory/eve/trunk/backend/core/src/java/org/apache/eve/db/SubstringEvaluator.java	Wed Sep 29 21:35:00 2004
@@ -16,11 +16,152 @@
  */
 package org.apache.eve.db;
 
+
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.schema.Normalizer;
+import org.apache.ldap.common.filter.SubstringNode;
+
+import org.apache.eve.schema.NormalizerRegistry;
+
+
 /**
- *
+ * Evaluates substring filter assertions on an entry.
+ * 
  * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
-public interface SubstringEvaluator extends Evaluator
+public class SubstringEvaluator implements Evaluator
 {
-}
\ No newline at end of file
+    /** Database used while evaluating candidates */
+    private Database db;
+    /** Normalizer registry for up value normalization */
+    private NormalizerRegistry normalizerRegistry;
+
+
+    public SubstringEvaluator( Database db, NormalizerRegistry normReg )
+    {
+        this.db = db;
+        this.normalizerRegistry = normReg;
+    }
+
+
+    /**
+     * @see org.apache.eve.db.Evaluator#evaluate(ExprNode, IndexRecord)
+     */
+    public boolean evaluate( ExprNode node, IndexRecord record )
+        throws NamingException
+    {
+        RE regex = null; 
+        SubstringNode snode = ( SubstringNode ) node;
+
+        if ( db.hasUserIndexOn( snode.getAttribute() ) )
+        {
+            Index idx = db.getUserIndex( snode.getAttribute() );
+        
+            /*
+             * Note that this is using the reverse half of the index giving a 
+             * considerable performance improvement on this kind of operation.
+             * Otherwise we would have to scan the entire index if there were
+             * no reverse lookups.
+             */
+        
+            NamingEnumeration list = idx.listReverseIndices( record.getEntryId() );
+
+            // compile the regular expression to search for a matching attribute
+            try 
+            {
+                regex = snode.getRegex();
+            } 
+            catch ( RESyntaxException e ) 
+            {
+                NamingException ne = new NamingException( "SubstringNode '" 
+                    + node + "' had " + "incorrect syntax" );
+                ne.setRootCause( e );
+                throw ne;
+            }
+
+            // cycle through the attribute values testing for a match
+            while ( list.hasMore() ) 
+            {
+                IndexRecord rec = ( IndexRecord ) list.next();
+            
+                // once match is found cleanup and return true
+                if ( regex.match( ( String ) rec.getIndexKey() ) ) 
+                {
+                    list.close();
+                    return true;
+                }
+            }
+
+            // we fell through so a match was not found - assertion was false.
+            return false;
+        }
+
+        // --------------------------------------------------------------------
+        // Index not defined beyond this point
+        // --------------------------------------------------------------------
+        
+        Attribute attr = null;
+        Normalizer normalizer = normalizerRegistry.getSubstring( snode.getAttribute() );
+
+        // resusitate the entry if it has not been and set entry in IndexRecord
+        if ( null == record.getAttributes() )
+        {
+            Attributes attrs = db.lookup( record.getEntryId() );
+            record.setAttributes( attrs );
+        }
+        
+        // get the attribute
+        attr = record.getAttributes().get( snode.getAttribute() );
+        
+        // if the attribute does not exist just return false
+        if ( null == attr )
+        {
+            return false;
+        }
+
+        // compile the regular expression to search for a matching attribute
+        try 
+        {
+            regex = snode.getRegex();
+        } 
+        catch ( RESyntaxException e ) 
+        {
+            NamingException ne = new NamingException( "SubstringNode '" 
+                + node + "' had " + "incorrect syntax" );
+            ne.setRootCause( e );
+            throw ne;
+        }
+        
+        /*
+         * Cycle through the attribute values testing normalized version 
+         * obtained from using the substring matching rule's normalizer.
+         * The test uses the comparator obtained from the appropriate 
+         * substring matching rule.
+         */ 
+        NamingEnumeration list = attr.getAll(); 
+        while ( list.hasMore() ) 
+        {
+            String value = ( String ) 
+                normalizer.normalize( list.next() );
+            
+            // Once match is found cleanup and return true
+            if ( regex.match( value ) ) 
+            {
+                list.close();
+                return true;
+            }
+        }
+
+        // we fell through so a match was not found - assertion was false.
+        return false;
+    }
+}