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 2005/10/25 06:20:35 UTC

svn commit: r328253 - in /directory/apacheds/trunk: core/src/main/java/org/apache/ldap/server/normalization/ main/src/test/org/apache/ldap/server/

Author: akarasulu
Date: Mon Oct 24 21:20:27 2005
New Revision: 328253

URL: http://svn.apache.org/viewcvs?rev=328253&view=rev
Log:
changes ...

VNV = ValueNormalizationVisitor
NS = NormalizationService 

 o made the VNV prune away bogus leaves that contain undefined attributes
   instead of throwing an exception - even branches may now be pruned if
   they are left bare or with a single node in case of AND/OR branches
 o cleaned up NS considerably
    - parser need not be synchronized anymore since the parse method is 
      synchronized
    - removed unnecesary constructs in inner class when I added the attribute
      type registry as a member to the NS class
    - doco for members
    - logger added
 o added code in search() method of NS to check if the pruned filter makes sense
   if not it is altered.  i.e. if it is a leaf node and undefined an 
   EmptyEnumeration is returned and likewise if the filter is a branch node
   without children.  If the filter is an AND or OR node and has one child
   the child is returned instead of the filter node.
 o added test cases which failed before the changes and pass now with changes


Modified:
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/NormalizationService.java
    directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/ValueNormalizingVisitor.java
    directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/NormalizationService.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/NormalizationService.java?rev=328253&r1=328252&r2=328253&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/NormalizationService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/NormalizationService.java Mon Oct 24 21:20:27 2005
@@ -27,15 +27,20 @@
 import javax.naming.directory.SearchControls;
 
 import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.LeafNode;
+import org.apache.ldap.common.filter.BranchNode;
 import org.apache.ldap.common.name.DnParser;
 import org.apache.ldap.common.name.NameComponentNormalizer;
 import org.apache.ldap.common.schema.AttributeType;
+import org.apache.ldap.common.util.EmptyEnumeration;
 import org.apache.ldap.server.DirectoryServiceConfiguration;
 import org.apache.ldap.server.configuration.InterceptorConfiguration;
 import org.apache.ldap.server.interceptor.BaseInterceptor;
 import org.apache.ldap.server.interceptor.NextInterceptor;
 import org.apache.ldap.server.partition.DirectoryPartitionNexus;
 import org.apache.ldap.server.schema.AttributeTypeRegistry;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
 
 
 /**
@@ -48,22 +53,27 @@
  */
 public class NormalizationService extends BaseInterceptor
 {
+    /** logger used by this class */
+    private static final Logger log = LoggerFactory.getLogger( NormalizationService.class );
+
+    /** the parser used for normalizing distinguished names */
     private DnParser parser;
+    /** a filter node value normalizer and undefined node remover */
     private ValueNormalizingVisitor visitor;
+    /** the attributeType registry used for normalization and determining if some filter nodes are undefined */
+    private AttributeTypeRegistry registry;
 
 
     public void init( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
     {
-        AttributeTypeRegistry attributeRegistry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
-        NameComponentNormalizer ncn = new PerComponentNormalizer( attributeRegistry );
+        registry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
+        NameComponentNormalizer ncn = new PerComponentNormalizer();
         parser = new DnParser( ncn );
         visitor = new ValueNormalizingVisitor( ncn );
     }
 
 
-    public void destroy()
-    {
-    }
+    public void destroy() {}
 
 
     // ------------------------------------------------------------------------
@@ -73,149 +83,130 @@
 
     public void add( NextInterceptor nextInterceptor, String upName, Name normName, Attributes attrs ) throws NamingException
     {
-        synchronized( parser )
-        {
-            normName = parser.parse( normName.toString() );
-        }
-
+        normName = parser.parse( normName.toString() );
         nextInterceptor.add( upName, normName, attrs );
     }
 
 
     public void delete( NextInterceptor nextInterceptor, Name name ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         nextInterceptor.delete( name );
     }
 
 
     public void modify( NextInterceptor nextInterceptor, Name name, int modOp, Attributes attrs ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         nextInterceptor.modify( name, modOp, attrs );
     }
 
 
     public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         nextInterceptor.modify( name, items );
     }
 
 
     public void modifyRn( NextInterceptor nextInterceptor, Name name, String newRn, boolean deleteOldRn ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         nextInterceptor.modifyRn( name, newRn, deleteOldRn );
     }
 
 
     public void move( NextInterceptor nextInterceptor, Name name, Name newParentName ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-            newParentName = parser.parse( newParentName.toString() );
-        }
-
+        name = parser.parse( name.toString() );
+        newParentName = parser.parse( newParentName.toString() );
         nextInterceptor.move( name, newParentName );
     }
 
 
     public void move( NextInterceptor nextInterceptor, Name name, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-
-            newParentName = parser.parse( newParentName.toString() );
-        }
-
+        name = parser.parse( name.toString() );
+        newParentName = parser.parse( newParentName.toString() );
         nextInterceptor.move( name, newParentName, newRn, deleteOldRn );
     }
 
 
     public NamingEnumeration search( NextInterceptor nextInterceptor,
-            Name base, Map env, ExprNode filter,
-            SearchControls searchCtls ) throws NamingException
+                                     Name base, Map env, ExprNode filter,
+                                     SearchControls searchCtls ) throws NamingException
     {
-        synchronized( parser )
+        base = parser.parse( base.toString() );
+
+        if ( filter.isLeaf() )
         {
-            base = parser.parse( base.toString() );
+            LeafNode ln = ( LeafNode ) filter;
+            if ( ! registry.hasAttributeType( ln.getAttribute() ) )
+            {
+                StringBuffer buf = new StringBuffer();
+                buf.append( "undefined filter based on undefined attributeType '" );
+                buf.append( ln.getAttribute() );
+                buf.append( "' not evaluted at all.  Returning empty enumeration." );
+                log.warn( buf.toString() );
+                return new EmptyEnumeration();
+            }
         }
 
         filter.accept( visitor );
+
+        // check that after pruning we have valid branch node at the top 
+        if ( ! filter.isLeaf() )
+        {
+            BranchNode child = ( BranchNode ) filter;
+
+            // if the remaining filter branch node has no children return an empty enumeration
+            if ( child.getChildren().size() == 0 )
+            {
+                log.warn( "Undefined branchnode filter without child nodes not evaluted at all.  Returning empty enumeration." );
+                return new EmptyEnumeration();
+            }
+
+            // now for AND & OR nodes with a single child left replace them with their child
+            if ( child.getChildren().size() == 1 && child.getOperator() != BranchNode.NOT )
+            {
+                filter = child.getChild();
+            }
+        }
         return nextInterceptor.search( base, env, filter, searchCtls );
     }
 
 
     public boolean hasEntry( NextInterceptor nextInterceptor, Name name ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.hasEntry( name );
     }
 
 
     public boolean isSuffix( NextInterceptor nextInterceptor, Name name ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.isSuffix( name );
     }
 
 
     public NamingEnumeration list( NextInterceptor nextInterceptor, Name base ) throws NamingException
     {
-        synchronized( parser )
-        {
-            base = parser.parse( base.toString() );
-        }
-
+        base = parser.parse( base.toString() );
         return nextInterceptor.list( base );
     }
 
 
     public Attributes lookup( NextInterceptor nextInterceptor, Name name ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.lookup( name );
     }
 
 
     public Attributes lookup( NextInterceptor nextInterceptor, Name name, String[] attrIds ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.lookup( name, attrIds );
     }
 
@@ -227,36 +218,22 @@
 
     public Name getMatchedName( NextInterceptor nextInterceptor, Name name, boolean normalized ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.getMatchedName( name, normalized );
     }
 
 
     public Name getSuffix( NextInterceptor nextInterceptor, Name name, boolean normalized ) throws NamingException
     {
-        synchronized( parser )
-        {
-            name = parser.parse( name.toString() );
-        }
-
+        name = parser.parse( name.toString() );
         return nextInterceptor.getSuffix( name, normalized );
     }
 
 
     public boolean compare( NextInterceptor next, Name name, String oid, Object value ) throws NamingException
     {
-        Name normalized;
-
-        synchronized( parser )
-        {
-            normalized = parser.parse( name.toString() );
-        }
-
-        return next.compare( normalized, oid, value );
+        name = parser.parse( name.toString() );
+        return next.compare( name, oid, value );
     }
 
 
@@ -266,22 +243,6 @@
      */
     private class PerComponentNormalizer implements NameComponentNormalizer
     {
-        /** the attribute type registry we use to lookup component normalizers */
-        private final AttributeTypeRegistry registry;
-
-
-        /**
-         * Creates a name component normalizer that looks up normalizers using
-         * an AttributeTypeRegistry.
-         *
-         * @param registry the attribute type registry to get normalizers
-         */
-        public PerComponentNormalizer( AttributeTypeRegistry registry )
-        {
-            this.registry = registry;
-        }
-
-
         public String normalizeByName( String name, String value ) throws NamingException
         {
             AttributeType type = registry.lookup( name );
@@ -298,7 +259,7 @@
 
         public boolean isDefined( String id )
         {
-            return this.registry.hasAttributeType( id );
+            return registry.hasAttributeType( id );
         }
     }
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/ValueNormalizingVisitor.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/ValueNormalizingVisitor.java?rev=328253&r1=328252&r2=328253&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/ValueNormalizingVisitor.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/ldap/server/normalization/ValueNormalizingVisitor.java Mon Oct 24 21:20:27 2005
@@ -17,10 +17,7 @@
 package org.apache.ldap.server.normalization;
 
 
-import org.apache.ldap.common.filter.FilterVisitor;
-import org.apache.ldap.common.filter.ExprNode;
-import org.apache.ldap.common.filter.BranchNode;
-import org.apache.ldap.common.filter.SimpleNode;
+import org.apache.ldap.common.filter.*;
 import org.apache.ldap.common.name.NameComponentNormalizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,14 +27,27 @@
 
 
 /**
- * A filter visitor which normalizes leaf node values as it visits them.
+ * A filter visitor which normalizes leaf node values as it visits them.  It also removes
+ * leaf nodes from branches whose attributeType is undefined.  It obviously cannot remove
+ * a leaf node from a filter which is only a leaf node.  Checks to see if a filter is a
+ * leaf node with undefined attributeTypes should be done outside this visitor.
+ *
+ * Since this visitor may remove filter nodes it may produce negative results on filters,
+ * like NOT branch nodes without a child or AND and OR nodes with one or less children.  This
+ * might make some partition implementations choke.  To avoid this problem we clean up branch
+ * nodes that don't make sense.  For example all BranchNodes without children are just
+ * removed.  An AND and OR BranchNode with a single child is replaced with it's child for
+ * all but the topmost branchnode which we cannot replace.  So again the top most branch
+ * node must be inspected by code outside of this visitor.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$
  */
 public class ValueNormalizingVisitor implements FilterVisitor
 {
+    /** logger used by this class */
     private final static Logger log = LoggerFactory.getLogger( ValueNormalizingVisitor.class );
+    /** the name component normalizer used by this visitor */
     private final NameComponentNormalizer ncn;
 
 
@@ -52,11 +62,17 @@
         if ( node instanceof SimpleNode )
         {
             SimpleNode snode = ( SimpleNode ) node;
-            String normalized = null;
+            String normalized;
 
             try
             {
-                if ( Character.isDigit( snode.getAttribute().charAt( 0 ) ) )
+                // still need this check here in case the top level is a leaf node
+                // with an undefined attributeType for its attribute
+                if ( ! ncn.isDefined( snode.getAttribute() ) )
+                {
+                    normalized = snode.getValue();
+                }
+                else if ( Character.isDigit( snode.getAttribute().charAt( 0 ) ) )
                 {
                     normalized = ncn.normalizeByOid( snode.getAttribute(), snode.getValue() );
                 }
@@ -75,13 +91,78 @@
             return;
         }
 
-        if (node instanceof BranchNode)
+        if ( node instanceof BranchNode )
         {
             BranchNode bnode = ( BranchNode ) node;
-            final int size = bnode.getChildren().size();
-            for ( int ii = 0; ii < size ; ii++ )
+            StringBuffer buf = null;
+            for ( int ii = 0; ii < bnode.getChildren().size() ; ii++ )
+            {
+                // before visiting each node let's check to make sure non-branch children use
+                // attributes that are defined in the system, if undefined nodes are removed
+                ExprNode child = ( ExprNode ) bnode.getChildren().get( ii );
+                if ( child.isLeaf() )
+                {
+                    LeafNode ln = ( LeafNode ) child;
+                    if ( ! ncn.isDefined( ln.getAttribute() ) )
+                    {
+                        if ( buf == null )
+                        {
+                            buf = new StringBuffer();
+                        }
+                        else
+                        {
+                            buf.setLength( 0 );
+                        }
+                        buf.append( "Removing leaf node based on undefined attribute '" );
+                        buf.append( ln.getAttribute() );
+                        buf.append( "' from filter." );
+                        log.warn( buf.toString() );
+
+                        // remove the child at ii
+                        bnode.getChildren().remove( child );
+                        ii--; // decrement so we can evaluate next child which has shifted to ii
+                        continue;
+                    }
+                }
+
+                visit( child );
+            }
+
+            // now see if any branch child nodes are damaged (NOT without children,
+            // AND/OR with one or less children) and repair them by removing branch
+            // nodes without children and replacing branch nodes like AND/OR with
+            // their single child if other branch nodes do not remain.
+            for ( int ii = 0; ii < bnode.getChildren().size() ; ii++ )
             {
-                visit( ( ExprNode ) bnode.getChildren().get( ii ) );
+                ExprNode unknown = ( ExprNode ) bnode.getChildren().get( ii );
+                if ( !unknown.isLeaf() )
+                {
+                    BranchNode child = ( BranchNode ) unknown;
+
+                    // remove child branch node that has no children left
+                    if ( child.getChildren().size() == 0 )
+                    {
+                        // remove the child at ii
+                        bnode.getChildren().remove( child );
+                        ii--; // decrement so we can evaluate next child which has shifted to ii
+                        continue;
+                    }
+
+                    // now for AND & OR nodes with a single child left replace them
+                    // with their child at the same index they AND/OR node was in
+                    if ( child.getChildren().size() == 1 && child.getOperator() != BranchNode.NOT )
+                    {
+                        bnode.getChildren().remove( child );
+                        if ( ii >= bnode.getChildren().size() )
+                        {
+                            bnode.getChildren().add( child.getChild() );
+                        }
+                        else
+                        {
+                            bnode.getChildren().add( ii, child.getChild() );
+                        }
+                    }
+                }
             }
         }
     }

Modified: directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java
URL: http://svn.apache.org/viewcvs/directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java?rev=328253&r1=328252&r2=328253&view=diff
==============================================================================
--- directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java (original)
+++ directory/apacheds/trunk/main/src/test/org/apache/ldap/server/MiscTest.java Mon Oct 24 21:20:27 2005
@@ -18,6 +18,7 @@
 
 
 import org.apache.ldap.server.configuration.MutableDirectoryPartitionConfiguration;
+import org.apache.ldap.common.util.EmptyEnumeration;
 
 import java.util.Hashtable;
 import java.util.Set;
@@ -230,5 +231,27 @@
 
         InitialDirContext userCtx = new InitialDirContext( env );
         assertNotNull( userCtx );
+    }
+
+
+    /**
+     * Tests to make sure undefined attributes in filter assertions are pruned and do not
+     * result in exceptions.
+     */
+    public void testBogusAttributeInSearchFilter() throws Exception
+    {
+        SearchControls cons = new SearchControls();
+        NamingEnumeration e = sysRoot.search( "", "(bogusAttribute=abc123)", cons );
+        assertNotNull( e );
+        assertEquals( e.getClass(), EmptyEnumeration.class );
+        e = sysRoot.search( "", "(!(bogusAttribute=abc123))", cons );
+        assertNotNull( e );
+        assertEquals( e.getClass(), EmptyEnumeration.class );
+        e = sysRoot.search( "", "(& (bogusAttribute=abc123)(bogusAttribute=abc123) )", cons );
+        assertNotNull( e );
+        assertEquals( e.getClass(), EmptyEnumeration.class );
+        e = sysRoot.search( "", "(& (bogusAttribute=abc123)(ou=abc123) )", cons );
+        assertNotNull( e );
+        assertFalse( e.getClass().equals( EmptyEnumeration.class ) );
     }
 }