You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2011/10/15 00:36:15 UTC

svn commit: r1183537 [4/11] - in /directory/apacheds/trunk/interceptors: admin/ admin/.settings/ authn/ authn/.settings/ authz/.settings/ changelog/ changelog/src/ changelog/src/main/ changelog/src/main/java/ changelog/src/main/java/org/ changelog/src/...

Added: directory/apacheds/trunk/interceptors/logger/src/main/java/org/apache/directory/server/core/logger/TimerInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/logger/src/main/java/org/apache/directory/server/core/logger/TimerInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/logger/src/main/java/org/apache/directory/server/core/logger/TimerInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/logger/src/main/java/org/apache/directory/server/core/logger/TimerInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,571 @@
+/*
+ *  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.core.logger;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.Interceptor;
+import org.apache.directory.server.core.api.interceptor.NextInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.EntryOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.GetRootDSEOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ListOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An interceptor used to log times to process each operation.
+ * 
+ * The way it works is that it gathers the time to process an operation 
+ * into a global counter, which is logged every 1000 operations (when 
+ * using the OPERATION_STATS logger). It's also possible to get the time for
+ * each single operation if activating the OPERATION_TIME logger.
+ * 
+ * Thos two loggers must be set to DEBUG.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TimerInterceptor implements Interceptor
+{
+    /** A aggregating logger */
+    private static final Logger OPERATION_STATS = LoggerFactory.getLogger( "OPERATION_STATS" );
+
+    /** An operation logger */
+    private static final Logger OPERATION_TIME = LoggerFactory.getLogger( "OPERATION_TIME" );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG_STATS = OPERATION_STATS.isDebugEnabled();
+    private static final boolean IS_DEBUG_TIME = OPERATION_TIME.isDebugEnabled();
+
+    /** The Logger's name */
+    private String name;
+    
+    /** Stats for the add operation */
+    private static AtomicLong totalAdd = new AtomicLong( 0 );
+    private static AtomicInteger nbAddCalls = new AtomicInteger( 0 );
+
+    /** Stats for the bind operation */
+    private static AtomicLong totalBind = new AtomicLong( 0 );
+    private static AtomicInteger nbBindCalls = new AtomicInteger( 0 );
+
+    /** Stats for the compare operation */
+    private static AtomicLong totalCompare = new AtomicLong( 0 );
+    private static AtomicInteger nbCompareCalls = new AtomicInteger( 0 );
+
+    /** Stats for the delete operation */
+    private static AtomicLong totalDelete = new AtomicLong( 0 );
+    private static AtomicInteger nbDeleteCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the GetRootDSE operation */
+    private static AtomicLong totalGetRootDSE = new AtomicLong( 0 );
+    private static AtomicInteger nbGetRootDSECalls = new AtomicInteger( 0 );
+    
+    /** Stats for the HasEntry operation */
+    private static AtomicLong totalHasEntry = new AtomicLong( 0 );
+    private static AtomicInteger nbHasEntryCalls = new AtomicInteger( 0 );
+
+    /** Stats for the list operation */
+    private static AtomicLong totalList = new AtomicLong( 0 );
+    private static AtomicInteger nbListCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the lookup operation */
+    private static AtomicLong totalLookup = new AtomicLong( 0 );
+    private static AtomicInteger nbLookupCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the modify operation */
+    private static AtomicLong totalModify = new AtomicLong( 0 );
+    private static AtomicInteger nbModifyCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the move operation */
+    private static AtomicLong totalMove = new AtomicLong( 0 );
+    private static AtomicInteger nbMoveCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the moveAndRename operation */
+    private static AtomicLong totalMoveAndRename = new AtomicLong( 0 );
+    private static AtomicInteger nbMoveAndRenameCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the rename operation */
+    private static AtomicLong totalRename = new AtomicLong( 0 );
+    private static AtomicInteger nbRenameCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the search operation */
+    private static AtomicLong totalSearch = new AtomicLong( 0 );
+    private static AtomicInteger nbSearchCalls = new AtomicInteger( 0 );
+    
+    /** Stats for the unbind operation */
+    private static AtomicLong totalUnbind = new AtomicLong( 0 );
+    private static AtomicInteger nbUnbindCalls = new AtomicInteger( 0 );
+    
+    /**
+     * 
+     * Creates a new instance of TimerInterceptor.
+     *
+     * @param name This interceptor's name
+     */
+    public TimerInterceptor( String name )
+    {
+        this.name = name;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.add( addContext );
+        long delta = System.nanoTime() - t0;
+
+        if ( IS_DEBUG_STATS )
+        {
+            nbAddCalls.incrementAndGet();
+            totalAdd.getAndAdd( delta );
+    
+            if ( nbAddCalls.get() % 1000 == 0 )
+            {
+                long average = totalAdd.get()/(nbAddCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average add = {} microseconds, nb adds = {}", average, nbAddCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta add = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( NextInterceptor next, BindOperationContext bindContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.bind( bindContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbBindCalls.incrementAndGet();
+            totalBind.getAndAdd( delta );
+    
+            if ( nbBindCalls.get() % 1000 == 0 )
+            {
+                long average = totalBind.get()/(nbBindCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average bind = {} microseconds, nb binds = {}", average, nbBindCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta bind = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( NextInterceptor next, CompareOperationContext compareContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        boolean compare = next.compare( compareContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbCompareCalls.incrementAndGet();
+            totalCompare.getAndAdd( delta );
+    
+            if ( nbCompareCalls.get() % 1000 == 0 )
+            {
+                long average = totalCompare.get()/(nbCompareCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average compare = {} microseconds, nb compares = {}", average, nbCompareCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta compare = {}", name, delta );
+        }
+        
+        return compare;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.delete( deleteContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbDeleteCalls.incrementAndGet();
+            totalDelete.getAndAdd( delta );
+    
+            if ( nbDeleteCalls.get() % 1000 == 0 )
+            {
+                long average = totalDelete.get()/(nbDeleteCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average delete = {} microseconds, nb deletes = {}", average, nbDeleteCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta delete = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void destroy()
+    {
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry getRootDSE( NextInterceptor next, GetRootDSEOperationContext getRootDseContext )
+        throws LdapException
+    {
+        long t0 = System.nanoTime();
+        Entry rootDSE = next.getRootDSE( getRootDseContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbGetRootDSECalls.incrementAndGet();
+            totalGetRootDSE.getAndAdd( delta );
+    
+            if ( nbGetRootDSECalls.get() % 1000 == 0 )
+            {
+                long average = totalGetRootDSE.get()/(nbGetRootDSECalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average getRootDSE = {} microseconds, nb getRootDSEs = {}", average, nbGetRootDSECalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta getRootDSE = {}", name, delta );
+        }
+        
+        return rootDSE;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasEntry( NextInterceptor next, EntryOperationContext hasEntryContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        boolean hasEntry = next.hasEntry( hasEntryContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbHasEntryCalls.incrementAndGet();
+            totalHasEntry.getAndAdd( delta );
+    
+            if ( nbHasEntryCalls.get() % 1000 == 0 )
+            {
+                long average = totalHasEntry.get()/(nbHasEntryCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average hasEntry = {} microseconds, nb hasEntrys = {}", average, nbHasEntryCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta hasEntry = {}", name, delta );
+        }
+        
+        return hasEntry;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor list( NextInterceptor next, ListOperationContext listContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        EntryFilteringCursor cursor = next.list( listContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbListCalls.incrementAndGet();
+            totalList.getAndAdd( delta );
+    
+            if ( nbListCalls.get() % 1000 == 0 )
+            {
+                long average = totalList.get()/(nbListCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average list = {} microseconds, nb lists = {}", average, nbListCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta list = {}", name, delta );
+        }
+        
+        return cursor;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( NextInterceptor next, LookupOperationContext lookupContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        Entry entry = next.lookup( lookupContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbLookupCalls.incrementAndGet();
+            totalLookup.getAndAdd( delta );
+    
+            if ( nbLookupCalls.get() % 1000 == 0 )
+            {
+                long average = totalLookup.get()/(nbLookupCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average lookup = {} microseconds, nb lookups = {}", average, nbLookupCalls.get() );
+            }
+        }
+        
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta lookup = {}", name, delta );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.modify( modifyContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbModifyCalls.incrementAndGet();
+            totalModify.getAndAdd( delta );
+    
+            if ( nbModifyCalls.get() % 1000 == 0 )
+            {
+                long average = totalModify.get()/(nbModifyCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average modify = {} microseconds, nb modifys = {}", average, nbModifyCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta modify = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.move( moveContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbMoveCalls.incrementAndGet();
+            totalMove.getAndAdd( delta );
+    
+            if ( nbMoveCalls.get() % 1000 == 0 )
+            {
+                long average = totalMove.get()/(nbMoveCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average move = {} microseconds, nb moves = {}", average, nbMoveCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta move = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.moveAndRename( moveAndRenameContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbMoveAndRenameCalls.incrementAndGet();
+            totalMoveAndRename.getAndAdd( delta );
+    
+            if ( nbMoveAndRenameCalls.get() % 1000 == 0 )
+            {
+                long average = totalMoveAndRename.get()/(nbMoveAndRenameCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average moveAndRename = {} microseconds, nb moveAndRenames = {}", average, nbMoveAndRenameCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta moveAndRename = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.rename( renameContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbRenameCalls.incrementAndGet();
+            totalRename.getAndAdd( delta );
+    
+            if ( nbRenameCalls.get() % 1000 == 0 )
+            {
+                long average = totalRename.get()/(nbRenameCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average rename = {} microseconds, nb renames = {}", average, nbRenameCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta rename = {}", name, delta );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( NextInterceptor next, SearchOperationContext searchContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        EntryFilteringCursor cursor = next.search( searchContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbSearchCalls.incrementAndGet();
+            totalSearch.getAndAdd( delta );
+    
+            if ( nbSearchCalls.get() % 1000 == 0 )
+            {
+                long average = totalSearch.get()/(nbSearchCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average search = {} microseconds, nb searches = {}", average, nbSearchCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta search = {}", name, delta );
+        }
+        
+        return cursor;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unbind( NextInterceptor next, UnbindOperationContext unbindContext ) throws LdapException
+    {
+        long t0 = System.nanoTime();
+        next.unbind( unbindContext );
+        long delta = System.nanoTime() - t0;
+        
+        if ( IS_DEBUG_STATS )
+        {
+            nbUnbindCalls.incrementAndGet();
+            totalUnbind.getAndAdd( delta );
+    
+            if ( nbUnbindCalls.get() % 1000 == 0 )
+            {
+                long average = totalUnbind.get()/(nbUnbindCalls.get() * 1000);
+                OPERATION_STATS.debug( name + " : Average unbind = {} microseconds, nb unbinds = {}", average, nbUnbindCalls.get() );
+            }
+        }
+
+        if ( IS_DEBUG_TIME )
+        {
+            OPERATION_TIME.debug( "{} : Delta unbind = {}", name, delta );
+        }
+    }
+}

Propchange: directory/apacheds/trunk/interceptors/normalization/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Oct 14 22:36:08 2011
@@ -0,0 +1,11 @@
+target
+.project
+.classpath
+.settings
+eclipse-classes
+*.log
+*.iml
+*.ipr
+dependency-reduced-pom.xml
+META-INF
+

Added: directory/apacheds/trunk/interceptors/normalization/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/normalization/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-interceptors</artifactId>
+    <version>2.0.0-M4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>apacheds-interceptors-normalization</artifactId>
+  <name>ApacheDS Normalization Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Normalization interceptor
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-aci</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-trigger</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>bouncycastle</groupId>
+      <artifactId>bcprov-jdk15</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target/server-work</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.gif</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+</project>
+

Added: directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/ExpandingVisitor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/ExpandingVisitor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/ExpandingVisitor.java (added)
+++ directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/ExpandingVisitor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,185 @@
+/*
+ *  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.core.normalization;
+
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.filter.ApproximateNode;
+import org.apache.directory.shared.ldap.model.filter.BranchNode;
+import org.apache.directory.shared.ldap.model.filter.EqualityNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.shared.ldap.model.filter.FilterVisitor;
+import org.apache.directory.shared.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.shared.ldap.model.filter.LeafNode;
+import org.apache.directory.shared.ldap.model.filter.LessEqNode;
+import org.apache.directory.shared.ldap.model.filter.OrNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+
+
+/**
+ *
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ExpandingVisitor implements FilterVisitor
+{
+    /** The schemaManager */
+    private SchemaManager schemaManager;
+    
+    
+    /**
+     * 
+     * Creates a new instance of ExpandingVisitor.
+     *
+     * @param schemaManager The server schemaManager
+     */
+    public ExpandingVisitor( SchemaManager schemaManager )
+    {
+        this.schemaManager = schemaManager;
+    }
+
+
+    public boolean canVisit( ExprNode node )
+    {
+        return node instanceof BranchNode;
+    }
+
+
+    public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
+    {
+        return children;
+    }
+
+
+    public boolean isPrefix()
+    {
+        return false;
+    }
+
+
+    public Object visit( ExprNode node )
+    {
+        BranchNode bnode = ( BranchNode ) node;
+
+        // --------------------------------------------------------------------
+        // we want to check each child leaf node to see if it must be expanded
+        // children that are branch nodes are recursively visited
+        // --------------------------------------------------------------------
+
+        final List<ExprNode> children = bnode.getChildren();
+        int childNumber = 0;
+
+        for ( ExprNode child : children )
+        {
+            if ( child instanceof LeafNode )
+            {
+                LeafNode leaf = ( LeafNode ) child;
+
+                try
+                {
+                    if ( schemaManager.getAttributeTypeRegistry().hasDescendants( leaf.getAttributeType() ) )
+                    {
+                        // create a new OR node to hold all descendent forms
+                        // add to this node the generalized leaf node and 
+                        // replace the old leaf with the new OR branch node
+                        BranchNode orNode = new OrNode();
+                        orNode.getChildren().add( leaf );
+                        children.set( childNumber++, orNode );
+
+                        // iterate through descendants adding them to the orNode
+                        Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( leaf.getAttributeType() );
+
+                        while ( descendants.hasNext() )
+                        {
+                            LeafNode newLeaf = null;
+                            AttributeType descendant = descendants.next();
+
+                            if ( leaf instanceof PresenceNode )
+                            {
+                                newLeaf = new PresenceNode( descendant );
+                            }
+                            else if ( leaf instanceof ApproximateNode )
+                            {
+                                ApproximateNode approximateNode = ( ApproximateNode ) leaf;
+
+                                newLeaf = new ApproximateNode( descendant, approximateNode.getValue() );
+                            }
+                            else if ( leaf instanceof EqualityNode )
+                            {
+                                EqualityNode equalityNode = (EqualityNode) leaf;
+
+                                newLeaf = new EqualityNode( descendant, equalityNode.getValue() );
+                            }
+                            else if ( leaf instanceof GreaterEqNode )
+                            {
+                                GreaterEqNode greaterEqNode = ( GreaterEqNode ) leaf;
+
+                                newLeaf = new GreaterEqNode( descendant, greaterEqNode.getValue() );
+                            }
+                            else if ( leaf instanceof LessEqNode )
+                            {
+                                LessEqNode lessEqNode = ( LessEqNode ) leaf;
+
+                                newLeaf = new LessEqNode( descendant, lessEqNode.getValue() );
+                            }
+                            else if ( leaf instanceof ExtensibleNode )
+                            {
+                                ExtensibleNode extensibleNode = ( ExtensibleNode ) leaf;
+                                newLeaf = new ExtensibleNode( descendant, extensibleNode.getValue(),
+                                    extensibleNode.getMatchingRuleId(), extensibleNode.hasDnAttributes() );
+                            }
+                            else if ( leaf instanceof SubstringNode )
+                            {
+                                SubstringNode substringNode = ( SubstringNode ) leaf;
+                                newLeaf = new SubstringNode( descendant, substringNode.getInitial(),
+                                    substringNode.getFinal() );
+                            }
+                            else
+                            {
+                                throw new IllegalStateException( I18n.err( I18n.ERR_260, leaf ) );
+                            }
+
+                            orNode.addNode( newLeaf );
+                        }
+                    }
+                }
+                catch ( LdapException e )
+                {
+                    // log something here and throw a runtime excpetion
+                    throw new RuntimeException( I18n.err( I18n.ERR_261 ) );
+                }
+            }
+            else
+            {
+                visit( child );
+            }
+        } // end for loop
+
+        return null;
+    }
+}

Added: directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/FilterNormalizingVisitor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/FilterNormalizingVisitor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/FilterNormalizingVisitor.java (added)
+++ directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/FilterNormalizingVisitor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,511 @@
+/*
+ *  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.core.normalization;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.shared.ldap.model.entry.StringValue;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.filter.AndNode;
+import org.apache.directory.shared.ldap.model.filter.BranchNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.shared.ldap.model.filter.FilterVisitor;
+import org.apache.directory.shared.ldap.model.filter.LeafNode;
+import org.apache.directory.shared.ldap.model.filter.NotNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.filter.SimpleNode;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * 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 branch node 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>
+ */
+public class FilterNormalizingVisitor implements FilterVisitor
+{
+    /** logger used by this class */
+    private static final Logger log = LoggerFactory.getLogger( FilterNormalizingVisitor.class );
+
+    /** the name component normalizer used by this visitor */
+    private final NameComponentNormalizer ncn;
+
+    /** the SchemaManager instance used to resolve OIDs for attributeType ids */
+    private final SchemaManager schemaManager;
+
+    /**
+     * Chars which need to be escaped in a filter
+     * '\0' | '(' | ')' | '*' | '\'
+     */
+    private static final boolean[] FILTER_CHAR =
+        { true, false, false, false, false, false, false, false, // 00 -> 07 NULL
+            false, false, false, false, false, false, false, false, // 08 -> 0F
+            false, false, false, false, false, false, false, false, // 10 -> 17
+            false, false, false, false, false, false, false, false, // 18 -> 1F
+            false, false, false, false, false, false, false, false, // 20 -> 27
+            true, true, true, false, false, false, false, false, // 28 -> 2F '(', ')', '*'
+            false, false, false, false, false, false, false, false, // 30 -> 37
+            false, false, false, false, false, false, false, false, // 38 -> 3F 
+            false, false, false, false, false, false, false, false, // 40 -> 47
+            false, false, false, false, false, false, false, false, // 48 -> 4F
+            false, false, false, false, false, false, false, false, // 50 -> 57
+            false, false, false, false, true, false, false, false, // 58 -> 5F '\'
+            false, false, false, false, false, false, false, false, // 60 -> 67
+            false, false, false, false, false, false, false, false, // 68 -> 6F
+            false, false, false, false, false, false, false, false, // 70 -> 77
+            false, false, false, false, false, false, false, false // 78 -> 7F
+        };
+
+
+    /**
+     * Check if the given char is a filter escaped char
+     * &lt;filterEscapedChars&gt; ::= '\0' | '(' | ')' | '*' | '\'
+     *
+     * @param c the char we want to test
+     * @return true if the char is a pair char only
+     */
+    public static boolean isFilterChar( char c )
+    {
+        return ( ( ( c | 0x7F ) == 0x7F ) && FILTER_CHAR[c & 0x7f] );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of NormalizingVisitor.
+     *
+     * @param ncn The name component normalizer to use
+     * @param schemaManager The schemaManager
+     */
+    public FilterNormalizingVisitor( NameComponentNormalizer ncn, SchemaManager schemaManager )
+    {
+        this.ncn = ncn;
+        this.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * A private method used to normalize a value. At this point, the value
+     * is a Value<byte[]>, we have to translate it to a Value<String> if its
+     * AttributeType is H-R. Then we have to normalize the value accordingly
+     * to the AttributeType Normalizer.
+     * 
+     * @param attribute The attribute's ID
+     * @param value The value to normalize
+     * @return the normalized value
+     */
+    private Value<?> normalizeValue( AttributeType attributeType, Value<?> value )
+    {
+        try
+        {
+            Value<?> normalized = null;
+
+            if ( attributeType.getSyntax().isHumanReadable() )
+            {
+                normalized = new StringValue( ( String ) ncn.normalizeByName( attributeType.getOid(), value.getString() ) );
+            }
+            else
+            {
+                normalized = ( Value<?> ) ncn.normalizeByName( attributeType.getOid(), value.getBytes() );
+            }
+
+            return normalized;
+        }
+        catch ( LdapException ne )
+        {
+            log.warn( "Failed to normalize filter value: {}", ne.getLocalizedMessage(), ne );
+            return null;
+        }
+    }
+
+
+    /**
+     * Visit a PresenceNode. If the attribute exists, the node is returned, otherwise
+     * null is returned.
+     * 
+     * @param node the node to visit
+     * @return The visited node
+     */
+    private ExprNode visitPresenceNode( PresenceNode node ) throws LdapException
+    {
+        // still need this check here in case the top level is a leaf node
+        // with an undefined attributeType for its attribute
+        if ( !ncn.isDefined( node.getAttribute() ) )
+        {
+            return null;
+        }
+
+        node.setAttributeType( schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ) );
+
+        return node;
+    }
+
+
+    /**
+     * Visit a SimpleNode. If the attribute exists, the node is returned, otherwise
+     * null is returned. SimpleNodes are :
+     *  - ApproximateNode
+     *  - EqualityNode
+     *  - GreaterEqNode
+     *  - LesserEqNode
+     *  
+     * @param node the node to visit
+     * @return the visited node
+     */
+    private ExprNode visitSimpleNode( SimpleNode node ) throws LdapException
+    {
+        if ( node.getAttributeType() == null )
+        {
+            // still need this check here in case the top level is a leaf node
+            // with an undefined attributeType for its attribute
+            if ( !ncn.isDefined( node.getAttribute() ) )
+            {
+                return null;
+            }
+            
+            node.setAttributeType( schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ) );
+        }
+        
+        Value<?> normalized = normalizeValue( node.getAttributeType(), node.getValue() );
+
+        if ( normalized == null )
+        {
+            return null;
+        }
+
+        node.setValue( normalized );
+
+        return node;
+    }
+
+
+    /**
+     * Visit a SubstringNode. If the attribute exists, the node is returned, otherwise
+     * null is returned. 
+     * 
+     * Normalizing substring value is pretty complex. It's not currently implemented...
+     * 
+     * @param node the node to visit
+     * @return the visited node
+     */
+    private ExprNode visitSubstringNode( SubstringNode node ) throws LdapException
+    {
+        // still need this check here in case the top level is a leaf node
+        // with an undefined attributeType for its attribute
+        if ( !ncn.isDefined( node.getAttribute() ) )
+        {
+            return null;
+        }
+
+        node.setAttributeType( schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ) );
+
+        Value<?> normInitial = null;
+
+        if ( node.getInitial() != null )
+        {
+            normInitial = normalizeValue( node.getAttributeType(), new StringValue( node.getInitial() ) );
+
+            if ( normInitial == null )
+            {
+                return null;
+            }
+        }
+
+        List<String> normAnys = null;
+
+        if ( ( node.getAny() != null ) && ( node.getAny().size() != 0 ) )
+        {
+            normAnys = new ArrayList<String>( node.getAny().size() );
+
+            for ( String any : node.getAny() )
+            {
+                Value<?> normAny = normalizeValue( node.getAttributeType(), new StringValue( any ) );
+
+                if ( normAny != null )
+                {
+                    normAnys.add( normAny.getString() );
+                }
+            }
+
+            if ( normAnys.size() == 0 )
+            {
+                return null;
+            }
+        }
+
+        Value<?> normFinal = null;
+
+        if ( node.getFinal() != null )
+        {
+            normFinal = normalizeValue( node.getAttributeType(), new StringValue( node.getFinal() ) );
+
+            if ( normFinal == null )
+            {
+                return null;
+            }
+        }
+
+        if ( normInitial != null )
+        {
+            node.setInitial( normInitial.getString() );
+        }
+        else
+        {
+            node.setInitial( null );
+        }
+
+        node.setAny( normAnys );
+
+        if ( normFinal != null )
+        {
+            node.setFinal( normFinal.getString() );
+        }
+        else
+        {
+            node.setFinal( null );
+        }
+
+        return node;
+    }
+
+
+    /**
+     * Visit a ExtensibleNode. If the attribute exists, the node is returned, otherwise
+     * null is returned. 
+     * 
+     * TODO implement the logic for ExtensibleNode
+     * 
+     * @param node the node to visit
+     * @return the visited node
+     */
+    private ExprNode visitExtensibleNode( ExtensibleNode node ) throws LdapException
+    {
+        // still need this check here in case the top level is a leaf node
+        // with an undefined attributeType for its attribute
+        if ( !ncn.isDefined( node.getAttribute() ) )
+        {
+            return null;
+        }
+
+        node.setAttributeType( schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ) );
+
+        return node;
+    }
+
+
+    /**
+     * Visit a BranchNode. BranchNodes are :
+     *  - AndNode
+     *  - NotNode
+     *  - OrNode
+     *  
+     * @param node the node to visit
+     * @return the visited node
+     */
+    private ExprNode visitBranchNode( BranchNode node )
+    {
+        // Two differente cases :
+        // - AND or OR
+        // - NOT
+
+        if ( node instanceof NotNode )
+        {
+            // Manage the NOT
+            ExprNode child = node.getFirstChild();
+
+            ExprNode result = ( ExprNode ) visit( child );
+
+            if ( result == null )
+            {
+                return null;
+            }
+            else if ( result instanceof BranchNode )
+            {
+                List<ExprNode> newChildren = new ArrayList<ExprNode>( 1 );
+                newChildren.add( result );
+                node.setChildren( newChildren );
+                return node;
+            }
+            else if ( result instanceof LeafNode)
+            {
+                List<ExprNode> newChildren = new ArrayList<ExprNode>( 1 );
+                newChildren.add( result );
+                node.setChildren( newChildren );
+                return node;
+            }
+        }
+        else
+        {
+            // Manage AND and OR nodes.
+            BranchNode branchNode = node;
+            List<ExprNode> children = node.getChildren();
+
+            // For AND and OR, we may have more than one children.
+            // We may have to remove some of them, so let's create
+            // a new handler to store the correct nodes.
+            List<ExprNode> newChildren = new ArrayList<ExprNode>( children.size() );
+
+            // Now, iterate through all the children
+            for ( int i = 0; i < children.size(); i++ )
+            {
+                ExprNode child = children.get( i );
+
+                ExprNode result = ( ExprNode ) visit( child );
+
+                if ( result != null )
+                {
+                    // As the node is correct, add it to the children 
+                    // list.
+                    newChildren.add( result );
+                }
+            }
+
+            if ( ( branchNode instanceof AndNode ) && ( newChildren.size() != children.size() ) )
+            {
+                return null;
+            }
+
+            if ( newChildren.size() == 0 )
+            {
+                // No more children, return null
+                return null;
+            }
+            else if ( newChildren.size() == 1 )
+            {
+                // As we only have one child, return it
+                // to the caller.
+                return newChildren.get( 0 );
+            }
+            else
+            {
+                branchNode.setChildren( newChildren );
+            }
+        }
+
+        return node;
+    }
+
+
+    /**
+     * Visit the tree, normalizing the leaves and recusrsively visit the branches.
+     * 
+     * Here are the leaves we are visiting :
+     * - PresenceNode ( attr =* )
+     * - ExtensibleNode ( ? )
+     * - SubStringNode ( attr = *X*Y* )
+     * - ApproximateNode ( attr ~= value )
+     * - EqualityNode ( attr = value )
+     * - GreaterEqNode ( attr >= value )
+     * - LessEqNode ( attr <= value )
+     * 
+     * The PresencNode is managed differently from other nodes, as it just check
+     * for the attribute, not the value.
+     * 
+     * @param node the node to visit
+     * @return the visited node
+     */
+    public Object visit( ExprNode node )
+    {
+        try
+        {
+            // -------------------------------------------------------------------
+            // Handle PresenceNodes
+            // -------------------------------------------------------------------
+
+            if ( node instanceof PresenceNode )
+            {
+                return visitPresenceNode( ( PresenceNode ) node );
+            }
+
+            // -------------------------------------------------------------------
+            // Handle BranchNodes (AndNode, NotNode and OrNode)
+            // -------------------------------------------------------------------
+
+            else if ( node instanceof BranchNode )
+            {
+                return visitBranchNode( ( BranchNode ) node );
+            }
+
+            // -------------------------------------------------------------------
+            // Handle SimpleNodes (ApproximateNode, EqualityNode, GreaterEqNode,
+            // and LesserEqNode) 
+            // -------------------------------------------------------------------
+
+            else if ( node instanceof SimpleNode )
+            {
+                return visitSimpleNode( ( SimpleNode ) node );
+            }
+            else if ( node instanceof ExtensibleNode )
+            {
+                return visitExtensibleNode( ( ExtensibleNode ) node );
+            }
+            else if ( node instanceof SubstringNode )
+            {
+                return visitSubstringNode( ( SubstringNode ) node );
+            }
+            else
+            {
+                return null;
+            }
+        }
+        catch ( LdapException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    public boolean canVisit( ExprNode node )
+    {
+        return true;
+    }
+
+
+    public boolean isPrefix()
+    {
+        return false;
+    }
+
+
+    public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
+    {
+        return children;
+    }
+}

Added: directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java (added)
+++ directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/NormalizationInterceptor.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,449 @@
+/*
+ *  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.core.normalization;
+
+
+import java.util.List;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.core.api.filtering.BaseEntryFilteringCursor;
+import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.api.interceptor.NextInterceptor;
+import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.EntryOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ListOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.shared.ldap.model.cursor.EmptyCursor;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.Modification;
+import org.apache.directory.shared.ldap.model.entry.StringValue;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidAttributeTypeException;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.name.Ava;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.Rdn;
+import org.apache.directory.shared.ldap.model.schema.AttributeType;
+import org.apache.directory.shared.ldap.model.schema.normalizers.ConcreteNameComponentNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A name normalization service.  This service makes sure all relative and distinguished
+ * names are normalized before calls are made against the respective interface methods
+ * on {@link DefaultPartitionNexus}.
+ *
+ * The Filters are also normalized.
+ *
+ * If the Rdn AttributeTypes are not present in the entry for an Add request,
+ * they will be added.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class NormalizationInterceptor extends BaseInterceptor
+{
+    /** logger used by this class */
+    private static final Logger LOG = LoggerFactory.getLogger( NormalizationInterceptor.class );
+
+    /** a filter node value normalizer and undefined node remover */
+    private FilterNormalizingVisitor normVisitor;
+
+    /**
+     * Initialize the registries, normalizers.
+     */
+    public void init( DirectoryService directoryService ) throws LdapException
+    {
+        LOG.debug( "Initialiazing the NormalizationInterceptor" );
+
+        super.init( directoryService );
+
+        NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( schemaManager );
+        normVisitor = new FilterNormalizingVisitor( ncn, schemaManager );
+    }
+
+
+    /**
+     * The destroy method does nothing
+     */
+    public void destroy()
+    {
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Normalize all Name based arguments for ContextPartition interface operations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public void add( NextInterceptor nextInterceptor, AddOperationContext addContext ) throws LdapException
+    {
+        addContext.getDn().apply( schemaManager );
+        addContext.getEntry().getDn().apply( schemaManager );
+        addRdnAttributesToEntry( addContext.getDn(), addContext.getEntry() );
+        nextInterceptor.add( addContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( NextInterceptor nextInterceptor, DeleteOperationContext deleteContext ) throws LdapException
+    {
+        Dn dn = deleteContext.getDn();
+
+        if ( !dn.isSchemaAware() )
+        {
+            dn.apply( schemaManager );
+        }
+
+        nextInterceptor.delete( deleteContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( NextInterceptor nextInterceptor, ModifyOperationContext modifyContext ) throws LdapException
+    {
+        if ( !modifyContext.getDn().isSchemaAware() )
+        {
+            modifyContext.getDn().apply( schemaManager );
+        }
+
+        if ( modifyContext.getModItems() != null )
+        {
+            for ( Modification modification : modifyContext.getModItems() )
+            {
+                AttributeType attributeType = schemaManager.getAttributeType( modification.getAttribute().getId() );
+                modification.apply( attributeType );
+            }
+        }
+        
+        nextInterceptor.modify( modifyContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( NextInterceptor nextInterceptor, RenameOperationContext renameContext ) throws LdapException
+    {
+        // Normalize the new Rdn and the Dn if needed
+
+        if ( !renameContext.getDn().isSchemaAware() )
+        {
+            renameContext.getDn().apply( schemaManager );
+        }
+
+        renameContext.getNewRdn().apply( schemaManager );
+
+        if ( !renameContext.getNewDn().isSchemaAware() )
+        {
+            renameContext.getNewDn().apply( schemaManager );
+        }
+
+        // Push to the next interceptor
+        nextInterceptor.rename( renameContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void move( NextInterceptor nextInterceptor, MoveOperationContext moveContext ) throws LdapException
+    {
+        if ( !moveContext.getDn().isSchemaAware() )
+        {
+            moveContext.getDn().apply( schemaManager );
+        }
+
+        if ( !moveContext.getOldSuperior().isSchemaAware() )
+        {
+            moveContext.getOldSuperior().apply( schemaManager );
+        }
+
+        if ( !moveContext.getNewSuperior().isSchemaAware() )
+        {
+            moveContext.getNewSuperior().apply( schemaManager );
+        }
+
+        if ( !moveContext.getNewDn().isSchemaAware() )
+        {
+            moveContext.getNewDn().apply( schemaManager );
+        }
+
+        if ( !moveContext.getRdn().isSchemaAware() )
+        {
+            moveContext.getRdn().apply( schemaManager );
+        }
+
+        nextInterceptor.move( moveContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void moveAndRename( NextInterceptor nextInterceptor, MoveAndRenameOperationContext moveAndRenameContext )
+        throws LdapException
+    {
+
+        if ( !moveAndRenameContext.getNewRdn().isSchemaAware() )
+        {
+            moveAndRenameContext.getNewRdn().apply( schemaManager );
+        }
+
+        if ( !moveAndRenameContext.getDn().isSchemaAware() )
+        {
+            moveAndRenameContext.getDn().apply( schemaManager );
+        }
+
+        if ( !moveAndRenameContext.getNewDn().isSchemaAware() )
+        {
+            moveAndRenameContext.getNewDn().apply( schemaManager );
+        }
+
+        if ( !moveAndRenameContext.getNewSuperiorDn().isSchemaAware() )
+        {
+            moveAndRenameContext.getNewSuperiorDn().apply( schemaManager );
+        }
+
+        nextInterceptor.moveAndRename( moveAndRenameContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext )
+        throws LdapException
+    {
+        Dn dn = searchContext.getDn();
+
+        if ( !dn.isSchemaAware() )
+        {
+            dn.apply( schemaManager );
+        }
+
+        ExprNode filter = searchContext.getFilter();
+
+        if ( filter == null )
+        {
+            LOG.warn( "undefined filter based on undefined attributeType not evaluted at all.  Returning empty enumeration." );
+            return new BaseEntryFilteringCursor( new EmptyCursor<Entry>(), searchContext );
+        }
+
+        // Normalize the filter
+        filter = ( ExprNode ) filter.accept( normVisitor );
+
+        if ( filter == null )
+        {
+            LOG.warn( "undefined filter based on undefined attributeType not evaluted at all.  Returning empty enumeration." );
+            return new BaseEntryFilteringCursor( new EmptyCursor<Entry>(), searchContext );
+        }
+        else
+        {
+            searchContext.setFilter( filter );
+
+            // TODO Normalize the returned Attributes, storing the UP attributes to format the returned values.
+            return nextInterceptor.search( searchContext );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasEntry( NextInterceptor nextInterceptor, EntryOperationContext hasEntryContext ) throws LdapException
+    {
+        hasEntryContext.getDn().apply( schemaManager );
+        return nextInterceptor.hasEntry( hasEntryContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext )
+        throws LdapException
+    {
+        listContext.getDn().apply( schemaManager );
+        return nextInterceptor.list( listContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    private String[] normalizeAttrsId( String[] attrIds ) throws LdapException
+    {
+        if ( attrIds == null )
+        {
+            return attrIds;
+        }
+
+        String[] normalizedAttrIds = new String[attrIds.length];
+        int pos = 0;
+
+        for ( String id : attrIds )
+        {
+            String oid = schemaManager.lookupAttributeTypeRegistry( id ).getOid();
+            normalizedAttrIds[pos++] = oid;
+        }
+
+        return normalizedAttrIds;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Entry lookup( NextInterceptor nextInterceptor, LookupOperationContext lookupContext ) throws LdapException
+    {
+        lookupContext.getDn().apply( schemaManager );
+
+        List<String> attrIds = lookupContext.getAttrsId();
+
+        if ( ( attrIds != null ) && ( attrIds.size() > 0 ) )
+        {
+            // We have to normalize the requested IDs
+            lookupContext.setAttrsId( normalizeAttrsId( lookupContext.getAttrsIdArray() ) );
+        }
+
+        return nextInterceptor.lookup( lookupContext );
+    }
+
+
+    // ------------------------------------------------------------------------
+    // Normalize all Name based arguments for other interface operations
+    // ------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( NextInterceptor next, CompareOperationContext compareContext ) throws LdapException
+    {
+        if ( !compareContext.getDn().isSchemaAware() )
+        {
+            compareContext.getDn().apply( schemaManager );
+        }
+
+        // Get the attributeType from the OID
+        try
+        {
+            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( compareContext.getOid() );
+
+            // Translate the value from binary to String if the AT is HR
+            if ( attributeType.getSyntax().isHumanReadable() && ( !compareContext.getValue().isHumanReadable() ) )
+            {
+                String value = compareContext.getValue().getString();
+                compareContext.setValue( new StringValue( value ) );
+            }
+
+            compareContext.setAttributeType( attributeType );
+        }
+        catch ( LdapException le )
+        {
+            throw new LdapInvalidAttributeTypeException( I18n.err( I18n.ERR_266, compareContext.getOid() ) );
+        }
+
+        return next.compare( compareContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind( NextInterceptor next, BindOperationContext bindContext ) throws LdapException
+    {
+        bindContext.getDn().apply( schemaManager );
+        next.bind( bindContext );
+    }
+
+
+    /**
+     * Adds missing Rdn's attributes and values to the entry.
+     *
+     * @param dn the Dn
+     * @param entry the entry
+     */
+    private void addRdnAttributesToEntry( Dn dn, Entry entry ) throws LdapException
+    {
+        if ( dn == null || entry == null )
+        {
+            return;
+        }
+
+        Rdn rdn = dn.getRdn();
+
+        // Loop on all the AVAs
+        for ( Ava ava : rdn )
+        {
+            Value<?> value = ava.getNormValue();
+            Value<?> upValue = ava.getUpValue();
+            String upId = ava.getUpType();
+
+            // Check that the entry contains this Ava
+            if ( !entry.contains( upId, value ) )
+            {
+                String message = "The Rdn '" + upId + "=" + upValue + "' is not present in the entry";
+                LOG.warn( message );
+
+                // We don't have this attribute : add it.
+                // Two cases :
+                // 1) The attribute does not exist
+                if ( !entry.containsAttribute( upId ) )
+                {
+                    entry.add( upId, value );
+                }
+                // 2) The attribute exists
+                else
+                {
+                    AttributeType at = schemaManager.lookupAttributeTypeRegistry( upId );
+
+                    // 2.1 if the attribute is single valued, replace the value
+                    if ( at.isSingleValued() )
+                    {
+                        entry.removeAttributes( upId );
+                        entry.add( upId, value );
+                    }
+                    // 2.2 the attribute is multi-valued : add the missing value
+                    else
+                    {
+                        entry.add( upId, value );
+                    }
+                }
+            }
+        }
+    }
+}

Added: directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/UndefinedFilterAttributeException.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/UndefinedFilterAttributeException.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/UndefinedFilterAttributeException.java (added)
+++ directory/apacheds/trunk/interceptors/normalization/src/main/java/org/apache/directory/server/core/normalization/UndefinedFilterAttributeException.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,69 @@
+/*
+ *  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.core.normalization;
+
+import org.apache.directory.shared.ldap.model.filter.LeafNode;
+
+
+/**
+ * A runtime exception thrown by visitors to denote the failure
+ * to recognize attributes in a filter expression tree.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UndefinedFilterAttributeException extends RuntimeException
+{
+    private static final long serialVersionUID = -8073762118319523479L;
+    private final LeafNode node;
+
+    
+    public UndefinedFilterAttributeException( LeafNode node )
+    {
+        super();
+        this.node = node;
+    }
+
+
+    public UndefinedFilterAttributeException( LeafNode node, String message )
+    {
+        super( message );
+        this.node = node;
+    }
+
+
+    public UndefinedFilterAttributeException( LeafNode node, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.node = node;
+    }
+
+
+    public UndefinedFilterAttributeException( LeafNode node, Throwable cause )
+    {
+        super( cause );
+        this.node = node;
+    }
+    
+
+    public LeafNode getUndefinedFilterNode()
+    {
+        return node;
+    }
+}

Added: directory/apacheds/trunk/interceptors/normalization/src/test/java/org/apache/directory/server/core/normalization/NormalizationVisitorTest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/normalization/src/test/java/org/apache/directory/server/core/normalization/NormalizationVisitorTest.java?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/normalization/src/test/java/org/apache/directory/server/core/normalization/NormalizationVisitorTest.java (added)
+++ directory/apacheds/trunk/interceptors/normalization/src/test/java/org/apache/directory/server/core/normalization/NormalizationVisitorTest.java Fri Oct 14 22:36:08 2011
@@ -0,0 +1,125 @@
+/*
+ *  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.core.normalization;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.ParseException;
+
+import org.apache.directory.shared.ldap.model.filter.EqualityNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.FilterParser;
+import org.apache.directory.shared.ldap.model.filter.NotNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.model.schema.normalizers.ConcreteNameComponentNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.NameComponentNormalizer;
+import org.apache.directory.shared.ldap.schemaloader.JarLdifSchemaLoader;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
+import org.apache.directory.shared.util.exception.Exceptions;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * A class to test the normalizing Visitor
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ *
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class NormalizationVisitorTest
+{
+    /** a filter node value normalizer and undefined node remover */
+    private static FilterNormalizingVisitor normVisitor;
+
+    /** A reference to the schemaManager */
+    private static SchemaManager schemaManager;
+
+
+    @BeforeClass
+    public static void init() throws Exception
+    {
+        JarLdifSchemaLoader loader = new JarLdifSchemaLoader();
+
+        schemaManager = new DefaultSchemaManager( loader );
+
+        boolean loaded = schemaManager.loadAllEnabled();
+
+        if ( !loaded )
+        {
+            fail( "Schema load failed : " + Exceptions.printErrors(schemaManager.getErrors()) );
+        }
+
+        NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( schemaManager );
+        normVisitor = new FilterNormalizingVisitor( ncn, schemaManager );
+    }
+
+
+    @Test
+    public void testSimpleFilter() throws ParseException
+    {
+        ExprNode filter = FilterParser.parse( schemaManager, "(ou=  test  1 )" );
+        ExprNode result = (ExprNode) filter.accept( normVisitor );
+
+        assertNotNull( result );
+        assertTrue( result instanceof EqualityNode<?>);
+        EqualityNode<?> equalityNode = ( EqualityNode<?> ) result;
+
+        assertEquals( "test 1", equalityNode.getValue().getNormValue() );
+        assertEquals( "2.5.4.11", equalityNode.getAttributeType().getOid() );
+    }
+
+
+    @Test
+    public void testPresenceFilter() throws ParseException
+    {
+        ExprNode filter = FilterParser.parse( schemaManager, "(ou=*)" );
+        ExprNode result = ( ExprNode ) filter.accept( normVisitor );
+
+        assertNotNull( result );
+        assertTrue( result instanceof PresenceNode);
+        PresenceNode presenceNode = ( PresenceNode ) result;
+
+        assertEquals( "2.5.4.11", presenceNode.getAttributeType().getOid() );
+    }
+
+
+    @Test
+    public void testBranchNormalizedVisitor() throws Exception
+    {
+        ExprNode filter = FilterParser.parse( schemaManager,
+            "(!(|(uniqueMember=cn=user1,ou=Test,dc=example,dc=com)(member=cn=user2,ou=Test,dc=example,dc=com)))" );
+        ExprNode result = ( ExprNode ) filter.accept( normVisitor );
+
+        assertNotNull( result );
+        assertTrue( result instanceof NotNode );
+    }
+
+}

Propchange: directory/apacheds/trunk/interceptors/operational/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Oct 14 22:36:08 2011
@@ -0,0 +1,11 @@
+target
+.project
+.classpath
+.settings
+eclipse-classes
+*.log
+*.iml
+*.ipr
+dependency-reduced-pom.xml
+META-INF
+

Added: directory/apacheds/trunk/interceptors/operational/pom.xml
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/operational/pom.xml?rev=1183537&view=auto
==============================================================================
--- directory/apacheds/trunk/interceptors/operational/pom.xml (added)
+++ directory/apacheds/trunk/interceptors/operational/pom.xml Fri Oct 14 22:36:08 2011
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-interceptors</artifactId>
+    <version>2.0.0-M4-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>apacheds-interceptors-operational</artifactId>
+  <name>ApacheDS Operational Attribute Interceptor</name>
+  <packaging>jar</packaging>
+
+  <description>
+    Operational Attribute interceptor
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-client-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-aci</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-trigger</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-util</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>bouncycastle</groupId>
+      <artifactId>bcprov-jdk15</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration> 
+          <systemPropertyVariables>
+            <workingDirectory>${basedir}/target/server-work</workingDirectory>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <excludes>
+          <exclude>**/*.gif</exclude>
+        </excludes>
+      </resource>
+    </resources>
+  </build>
+</project>
+