changes to allow selective interceptor bypasses from the proxy

git-svn-id: https://svn.apache.org/repos/asf/directory/apacheds/branches/interceptor-bypass@325990 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java b/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java
index 5702d86..201e6af 100644
--- a/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java
+++ b/core/src/main/java/org/apache/ldap/server/interceptor/InterceptorChain.java
@@ -17,12 +17,7 @@
 package org.apache.ldap.server.interceptor;

 

 

-import java.util.ArrayList;

-import java.util.HashMap;

-import java.util.Iterator;

-import java.util.List;

-import java.util.ListIterator;

-import java.util.Map;

+import java.util.*;

 

 import javax.naming.ConfigurationException;

 import javax.naming.Name;

@@ -34,10 +29,13 @@
 

 import org.apache.ldap.common.filter.ExprNode;

 import org.apache.ldap.server.DirectoryServiceConfiguration;

+import org.apache.ldap.server.invocation.Invocation;

+import org.apache.ldap.server.invocation.InvocationStack;

 import org.apache.ldap.server.configuration.DirectoryPartitionConfiguration;

 import org.apache.ldap.server.configuration.InterceptorConfiguration;

 import org.apache.ldap.server.configuration.MutableInterceptorConfiguration;

 import org.apache.ldap.server.partition.DirectoryPartitionNexus;

+import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;

 import org.slf4j.Logger;

 import org.slf4j.LoggerFactory;

 

@@ -453,10 +451,51 @@
     }

 

 

+    /**

+     * Gets the InterceptorEntry to use first with bypass information considered.

+     *

+     * @return the first entry to use.

+     */

+    private Entry getStartingEntry()

+    {

+        if ( InvocationStack.getInstance().isEmpty() )

+        {

+            return head;

+        }

+

+        Invocation invocation = InvocationStack.getInstance().peek();

+        if ( ! invocation.hasBypass() )

+        {

+            return head;

+        }

+

+        if ( ! invocation.isBypassed( DirectoryPartitionNexusProxy.BYPASS_ALL ) )

+        {

+            return tail;

+        }

+

+        Entry next = head;

+        while ( next != tail )

+        {

+            if ( invocation.isBypassed( next.configuration.getName() ) )

+            {

+                next = next.nextEntry;

+            }

+            else

+            {

+                return next;

+            }

+        }

+

+        return tail;

+    }

+

+

     public Attributes getRootDSE() throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.getRootDSE( next );

@@ -475,8 +514,9 @@
 

     public Name getMatchedName( Name name, boolean normalized ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.getMatchedName( next, name, normalized );

@@ -495,8 +535,9 @@
 

     public Name getSuffix( Name name, boolean normalized ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.getSuffix( next, name, normalized );

@@ -515,8 +556,9 @@
 

     public boolean compare( Name name, String oid, Object value ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.compare( next, name, oid, value );

@@ -535,8 +577,9 @@
 

     public Iterator listSuffixes( boolean normalized ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.listSuffixes( next, normalized );

@@ -554,8 +597,9 @@
 

     public void addContextPartition( DirectoryPartitionConfiguration cfg ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.addContextPartition( next, cfg );

@@ -573,8 +617,9 @@
 

     public void removeContextPartition( Name suffix ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.removeContextPartition( next, suffix );

@@ -592,8 +637,9 @@
 

     public void delete( Name name ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.delete( next, name );

@@ -611,8 +657,9 @@
 

     public void add( String upName, Name normName, Attributes entry ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry node = getStartingEntry();

+        Interceptor head = node.configuration.getInterceptor();

+        NextInterceptor next = node.nextInterceptor;

         try

         {

             head.add( next, upName, normName, entry );

@@ -630,8 +677,9 @@
 

     public void modify( Name name, int modOp, Attributes mods ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.modify( next, name, modOp, mods );

@@ -649,8 +697,9 @@
 

     public void modify( Name name, ModificationItem[] mods ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.modify( next, name, mods );

@@ -668,8 +717,9 @@
 

     public NamingEnumeration list( Name base ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.list( next, base );

@@ -688,8 +738,9 @@
 

     public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.search( next, base, env, filter, searchCtls );

@@ -708,8 +759,9 @@
 

     public Attributes lookup( Name name ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.lookup( next, name );

@@ -728,8 +780,9 @@
 

     public Attributes lookup( Name dn, String[] attrIds ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.lookup( next, dn, attrIds );

@@ -748,8 +801,9 @@
 

     public boolean hasEntry( Name name ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.hasEntry( next, name );

@@ -768,8 +822,9 @@
 

     public boolean isSuffix( Name name ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             return head.isSuffix( next, name );

@@ -788,8 +843,9 @@
 

     public void modifyRn( Name name, String newRn, boolean deleteOldRn ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.modifyRn( next, name, newRn, deleteOldRn );

@@ -807,8 +863,9 @@
 

     public void move( Name oriChildName, Name newParentName ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.move( next, oriChildName, newParentName );

@@ -826,8 +883,9 @@
 

     public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException

     {

-        Interceptor head = this.head.configuration.getInterceptor();

-        NextInterceptor next = this.head.nextInterceptor;

+        Entry entry = getStartingEntry();

+        Interceptor head = entry.configuration.getInterceptor();

+        NextInterceptor next = entry.nextInterceptor;

         try

         {

             head.move( next, oriChildName, newParentName, newRn, deleteOldRn );

@@ -870,13 +928,48 @@
             this.configuration = configuration;

             this.nextInterceptor = new NextInterceptor()

             {

+                private Entry getNextEntry()

+                {

+                    if ( InvocationStack.getInstance().isEmpty() )

+                    {

+                        return Entry.this.nextEntry;

+                    }

+

+                    Invocation invocation = InvocationStack.getInstance().peek();

+                    if ( ! invocation.hasBypass() )

+                    {

+                        return Entry.this.nextEntry;

+                    }

+

+                    if ( ! invocation.isBypassed( DirectoryPartitionNexusProxy.BYPASS_ALL ) )

+                    {

+                        return tail;

+                    }

+

+                    Entry next = Entry.this.nextEntry;

+                    while ( next != tail )

+                    {

+                        if ( invocation.isBypassed( next.configuration.getName() ) )

+                        {

+                            next = next.nextEntry;

+                        }

+                        else

+                        {

+                            return next;

+                        }

+                    }

+

+                    return next;

+                }

+

                 public boolean compare( Name name, String oid, Object value ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.compare( Entry.this.nextEntry.nextInterceptor, name, oid, value );

+                        return interceptor.compare( next.nextInterceptor, name, oid, value );

                     }

                     catch ( NamingException ne )

                     {

@@ -892,11 +985,12 @@
 

                 public Attributes getRootDSE() throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.getRootDSE( Entry.this.nextEntry.nextInterceptor );

+                        return interceptor.getRootDSE( next.nextInterceptor );

                     }

                     catch ( NamingException ne )

                     {

@@ -911,11 +1005,12 @@
 

                 public Name getMatchedName( Name dn, boolean normalized ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.getMatchedName( Entry.this.nextEntry.nextInterceptor, dn, normalized );

+                        return interceptor.getMatchedName( next.nextInterceptor, dn, normalized );

                     }

                     catch ( NamingException ne )

                     {

@@ -930,11 +1025,12 @@
 

                 public Name getSuffix( Name dn, boolean normalized ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.getSuffix( Entry.this.nextEntry.nextInterceptor, dn, normalized );

+                        return interceptor.getSuffix( next.nextInterceptor, dn, normalized );

                     }

                     catch ( NamingException ne )

                     {

@@ -949,11 +1045,12 @@
 

                 public Iterator listSuffixes( boolean normalized ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.listSuffixes( Entry.this.nextEntry.nextInterceptor, normalized );

+                        return interceptor.listSuffixes( next.nextInterceptor, normalized );

                     }

                     catch ( NamingException ne )

                     {

@@ -968,11 +1065,12 @@
 

                 public void delete( Name name ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.delete( Entry.this.nextEntry.nextInterceptor, name );

+                        interceptor.delete( next.nextInterceptor, name );

                     }

                     catch ( NamingException ne )

                     {

@@ -986,11 +1084,12 @@
 

                 public void add( String upName, Name normName, Attributes entry ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.add( Entry.this.nextEntry.nextInterceptor, upName, normName, entry );

+                        interceptor.add( next.nextInterceptor, upName, normName, entry );

                     }

                     catch ( NamingException ne )

                     {

@@ -1004,11 +1103,12 @@
 

                 public void modify( Name name, int modOp, Attributes mods ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.modify( Entry.this.nextEntry.nextInterceptor, name, modOp, mods );

+                        interceptor.modify( next.nextInterceptor, name, modOp, mods );

                     }

                     catch ( NamingException ne )

                     {

@@ -1022,11 +1122,12 @@
 

                 public void modify( Name name, ModificationItem[] mods ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.modify( Entry.this.nextEntry.nextInterceptor, name, mods );

+                        interceptor.modify( next.nextInterceptor, name, mods );

                     }

                     catch ( NamingException ne )

                     {

@@ -1040,11 +1141,12 @@
 

                 public NamingEnumeration list( Name base ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.list( Entry.this.nextEntry.nextInterceptor, base );

+                        return interceptor.list( next.nextInterceptor, base );

                     }

                     catch ( NamingException ne )

                     {

@@ -1059,11 +1161,12 @@
 

                 public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.search( Entry.this.nextEntry.nextInterceptor, base, env, filter, searchCtls );

+                        return interceptor.search( next.nextInterceptor, base, env, filter, searchCtls );

                     }

                     catch ( NamingException ne )

                     {

@@ -1078,11 +1181,12 @@
 

                 public Attributes lookup( Name name ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.lookup( Entry.this.nextEntry.nextInterceptor, name );

+                        return interceptor.lookup( next.nextInterceptor, name );

                     }

                     catch ( NamingException ne )

                     {

@@ -1097,11 +1201,12 @@
 

                 public Attributes lookup( Name dn, String[] attrIds ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.lookup( Entry.this.nextEntry.nextInterceptor, dn, attrIds );

+                        return interceptor.lookup( next.nextInterceptor, dn, attrIds );

                     }

                     catch ( NamingException ne )

                     {

@@ -1116,11 +1221,12 @@
 

                 public boolean hasEntry( Name name ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.hasEntry( Entry.this.nextEntry.nextInterceptor, name );

+                        return interceptor.hasEntry( next.nextInterceptor, name );

                     }

                     catch ( NamingException ne )

                     {

@@ -1135,11 +1241,12 @@
 

                 public boolean isSuffix( Name name ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        return interceptor.isSuffix( Entry.this.nextEntry.nextInterceptor, name );

+                        return interceptor.isSuffix( next.nextInterceptor, name );

                     }

                     catch ( NamingException ne )

                     {

@@ -1154,11 +1261,12 @@
 

                 public void modifyRn( Name name, String newRn, boolean deleteOldRn ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.modifyRn( Entry.this.nextEntry.nextInterceptor, name, newRn, deleteOldRn );

+                        interceptor.modifyRn( next.nextInterceptor, name, newRn, deleteOldRn );

                     }

                     catch ( NamingException ne )

                     {

@@ -1172,11 +1280,12 @@
 

                 public void move( Name oriChildName, Name newParentName ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.move( Entry.this.nextEntry.nextInterceptor, oriChildName, newParentName );

+                        interceptor.move( next.nextInterceptor, oriChildName, newParentName );

                     }

                     catch ( NamingException ne )

                     {

@@ -1190,11 +1299,12 @@
 

                 public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.move( Entry.this.nextEntry.nextInterceptor, oriChildName, newParentName, newRn, deleteOldRn );

+                        interceptor.move( next.nextInterceptor, oriChildName, newParentName, newRn, deleteOldRn );

                     }

                     catch ( NamingException ne )

                     {

@@ -1208,11 +1318,12 @@
 

                 public void addContextPartition( DirectoryPartitionConfiguration cfg ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.addContextPartition( Entry.this.nextEntry.nextInterceptor, cfg );

+                        interceptor.addContextPartition( next.nextInterceptor, cfg );

                     }

                     catch ( NamingException ne )

                     {

@@ -1227,11 +1338,12 @@
 

                 public void removeContextPartition( Name suffix ) throws NamingException

                 {

-                    Interceptor interceptor = Entry.this.nextEntry.configuration.getInterceptor();

+                    Entry next = getNextEntry();

+                    Interceptor interceptor = next.configuration.getInterceptor();

 

                     try

                     {

-                        interceptor.removeContextPartition( Entry.this.nextEntry.nextInterceptor, suffix );

+                        interceptor.removeContextPartition( next.nextInterceptor, suffix );

                     }

                     catch ( NamingException ne )

                     {

diff --git a/core/src/main/java/org/apache/ldap/server/invocation/Invocation.java b/core/src/main/java/org/apache/ldap/server/invocation/Invocation.java
index 4baeffb..9d3bc90 100644
--- a/core/src/main/java/org/apache/ldap/server/invocation/Invocation.java
+++ b/core/src/main/java/org/apache/ldap/server/invocation/Invocation.java
@@ -20,10 +20,12 @@
 import java.util.ArrayList;

 import java.util.Collections;

 import java.util.List;

+import java.util.Collection;

 

 import javax.naming.Context;

 

 import org.apache.ldap.server.partition.DirectoryPartitionNexus;

+import org.apache.ldap.server.partition.DirectoryPartitionNexusProxy;

 

 

 /**

@@ -37,27 +39,50 @@
     private final Context caller;

     private final String name;

     private final List parameters;

-    

+    private final Collection bypassed;

+    private final DirectoryPartitionNexusProxy proxy;

+

+

     /**

      * Creates a new instance that represents an invocation without parameters.

      * 

-     * @parem caller the JNDI {@link Context} that made this invocation

+     * @param caller the JNDI {@link Context} that made this invocation

      * @param name the name of the called method

      */

-    public Invocation( Context caller, String name )

+    public Invocation( DirectoryPartitionNexusProxy proxy, Context caller, String name )

     {

-        this( caller, name, null );

+        this( proxy, caller, name, null, Collections.EMPTY_SET );

     }

 

+

+    /**

+     * Creates a new instance.

+     *

+     * @param caller the JNDI {@link Context} that made this invocation

+     * @param name the name of the called method

+     * @param parameters the array of parameters passed to the called method

+     */

+    public Invocation( DirectoryPartitionNexusProxy proxy, Context caller, String name, Object[] parameters )

+    {

+        this( proxy, caller, name, parameters, Collections.EMPTY_SET );

+    }

+

+

     /**

      * Creates a new instance.

      * 

-     * @parem caller the JNDI {@link Context} that made this invocation

+     * @param caller the JNDI {@link Context} that made this invocation

      * @param name the name of the called method

      * @param parameters the array of parameters passed to the called method

+     * @param bypassed the set of bypassed Interceptor names

      */

-    public Invocation( Context caller, String name, Object[] parameters )

+    public Invocation( DirectoryPartitionNexusProxy proxy, Context caller, String name, Object[] parameters,

+                       Collection bypassed )

     {

+        if( proxy == null )

+        {

+            throw new NullPointerException( "proxy" );

+        }

         if( caller == null )

         {

             throw new NullPointerException( "caller" );

@@ -66,24 +91,44 @@
         {

             throw new NullPointerException( "name" );

         }

-        

+

         if( parameters == null )

         {

             parameters = new Object[ 0 ];

         }

-        

+

+        if ( bypassed == null )

+        {

+            this.bypassed = Collections.EMPTY_SET;

+        }

+        else

+        {

+            this.bypassed = Collections.unmodifiableCollection( bypassed );

+        }

+

+        this.proxy = proxy;

         this.caller = caller;

         this.name = name;

-        

+

         List paramList = new ArrayList();

         for( int i = 0; i < parameters.length; i++ )

         {

             paramList.add( parameters[ i ] );

         }

-        

+

         this.parameters = Collections.unmodifiableList( paramList );

     }

-    

+

+

+    /**

+     * Returns the proxy object to the {@link DirectoryPartitionNexus}.

+     */

+    public DirectoryPartitionNexusProxy getProxy()

+    {

+        return proxy;

+    }

+

+

     /**

      * Returns the JNDI {@link Context} which made this invocation.

      */

@@ -91,7 +136,8 @@
     {

         return caller;

     }

-    

+

+

     /**

      * Returns the name of the called method.

      */

@@ -99,7 +145,8 @@
     {

         return name;

     }

-    

+

+

     /**

      * Returns the list of parameters parameters passed to the called method.

      */

@@ -107,4 +154,27 @@
     {

         return parameters;

     }

+

+

+    /**

+     * Checks to see if an interceptor is bypassed.

+     *

+     * @param interceptorName the interceptorName of the interceptor to check for bypass

+     * @return true if the interceptor should be bypassed, false otherwise

+     */

+    public boolean isBypassed( String interceptorName )

+    {

+        return bypassed.contains( interceptorName );

+    }

+

+

+    /**

+     * Checks to see if any interceptors are bypassed by this Invocation.

+     *

+     * @return true if at least one bypass exists

+     */

+    public boolean hasBypass()

+    {

+        return !bypassed.isEmpty();

+    }

 }

diff --git a/core/src/main/java/org/apache/ldap/server/invocation/InvocationStack.java b/core/src/main/java/org/apache/ldap/server/invocation/InvocationStack.java
index 82315e5..bd71636 100644
--- a/core/src/main/java/org/apache/ldap/server/invocation/InvocationStack.java
+++ b/core/src/main/java/org/apache/ldap/server/invocation/InvocationStack.java
@@ -91,7 +91,15 @@
     {

         return ( Invocation ) this.stack.get( 0 );

     }

-    

+

+    /**

+     * Returns true if the stack is empty false otherwise.

+     */

+    public boolean isEmpty()

+    {

+        return this.stack.isEmpty();

+    }

+

     /**

      * Pushes the specified invocation to this stack.

      */

diff --git a/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java b/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java
index 5891de6..0ebd154 100644
--- a/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java
+++ b/core/src/main/java/org/apache/ldap/server/partition/DirectoryPartitionNexusProxy.java
@@ -19,6 +19,8 @@
 
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
 
 import javax.naming.Context;
 import javax.naming.Name;
@@ -28,6 +30,7 @@
 import javax.naming.directory.Attributes;
 import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
+import javax.naming.directory.DirContext;
 import javax.naming.event.EventContext;
 import javax.naming.event.NamingListener;
 import javax.naming.ldap.LdapContext;
@@ -54,6 +57,17 @@
  */
 public class DirectoryPartitionNexusProxy extends DirectoryPartitionNexus
 {
+    /** Bypass String to use when ALL interceptors should be skipped */
+    public static final String BYPASS_ALL = "*";
+    /** Bypass String to use when ALL interceptors should be skipped */
+    public static final Collection BYPASS_ALL_COLLECTION = Collections.singleton( BYPASS_ALL );
+    /** Integer const for DirContext.ADD_ATTRIBUTE */
+    private static final Integer ADD_MODOP = new Integer( DirContext.ADD_ATTRIBUTE );
+    /** Integer const for DirContext.REMOVE_ATTRIBUTE */
+    private static final Integer REMOVE_MODOP = new Integer( DirContext.REMOVE_ATTRIBUTE );
+    /** Integer const for DirContext.REPLACE_ATTRIBUTE */
+    private static final Integer REPLACE_MODOP = new Integer( DirContext.REPLACE_ATTRIBUTE );
+
     private final Context caller;
     private final DirectoryService service;
     private final DirectoryServiceConfiguration configuration;
@@ -105,12 +119,19 @@
         return this.service.isStarted();
     }
 
-    public Name getMatchedName(Name dn, boolean normalized) throws NamingException {
+
+    public Name getMatchedName( Name dn, boolean normalized ) throws NamingException
+    {
+        return getMatchedName( dn, normalized, null );
+    }
+
+
+    public Name getMatchedName( Name dn, boolean normalized, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "getMatchedDn",
-                new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE } ) );
+        Object[] args = new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE };
+        stack.push( new Invocation( this, caller, "getMatchedDn", args, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().getMatchedName( dn, normalized );
@@ -121,12 +142,19 @@
         }
     }
 
-    public Name getSuffix(Name dn, boolean normalized) throws NamingException {
+
+    public Name getSuffix( Name dn, boolean normalized) throws NamingException
+    {
+        return getSuffix( dn, normalized, null );
+    }
+
+
+    public Name getSuffix( Name dn, boolean normalized, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "getSuffix",
-                new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE } ) );
+        Object[] args = new Object[] { dn, normalized? Boolean.TRUE : Boolean.FALSE };
+        stack.push( new Invocation( this, caller, "getSuffix", args, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().getSuffix( dn, normalized );
@@ -137,12 +165,19 @@
         }
     }
 
-    public Iterator listSuffixes(boolean normalized) throws NamingException {
+
+    public Iterator listSuffixes( boolean normalized ) throws NamingException
+    {
+        return listSuffixes( normalized, null );
+    }
+
+
+    public Iterator listSuffixes( boolean normalized, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "listSuffixes",
-                new Object[] { normalized? Boolean.TRUE : Boolean.FALSE } ) );
+        Object[] args = new Object[] { normalized? Boolean.TRUE : Boolean.FALSE };
+        stack.push( new Invocation( this, caller, "listSuffixes", args, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().listSuffixes( normalized );
@@ -153,11 +188,18 @@
         }
     }
 
+
     public boolean compare( Name name, String oid, Object value ) throws NamingException
     {
+        return compare( name, oid, value, null );
+    }
+
+
+    public boolean compare( Name name, String oid, Object value, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation( caller, "compare", new Object[] { name, oid, value } ) );
+        stack.push( new Invocation( this, caller, "compare", new Object[] { name, oid, value }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().compare( name, oid, value );
@@ -169,12 +211,17 @@
     }
 
 
-    public void delete(Name name) throws NamingException {
+    public void delete( Name name ) throws NamingException
+    {
+        delete( name, null );
+    }
+
+
+    public void delete( Name name, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "delete",
-                new Object[] { name } ) );
+        stack.push( new Invocation( this, caller, "delete", new Object[] { name }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().delete( name );
@@ -185,12 +232,18 @@
         }
     }
 
-    public void add(String upName, Name normName, Attributes entry) throws NamingException {
+
+    public void add( String upName, Name normName, Attributes entry ) throws NamingException
+    {
+        add( upName, normName, entry, null );
+    }
+
+
+    public void add( String upName, Name normName, Attributes entry, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "add",
-                new Object[] { upName, normName, entry } ) );
+        stack.push( new Invocation( this, caller, "add", new Object[] { upName, normName, entry }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().add( upName, normName, entry );
@@ -201,13 +254,35 @@
         }
     }
 
-    public void modify(Name name, int modOp, Attributes mods) throws NamingException {
+
+    public void modify( Name name, int modOp, Attributes mods ) throws NamingException
+    {
+        modify( name, modOp, mods, null );
+    }
+
+
+    public void modify( Name name, int modOp, Attributes mods, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        // TODO Use predefined modOp Interger constants.
-        stack.push( new Invocation(
-                caller, "modify",
-                new Object[] { name, new Integer( modOp ), mods } ) );
+        Integer modOpObj;
+
+        switch( modOp )
+        {
+            case( DirContext.ADD_ATTRIBUTE ):
+                modOpObj = ADD_MODOP;
+                break;
+            case( DirContext.REMOVE_ATTRIBUTE ):
+                modOpObj = REMOVE_MODOP;
+                break;
+            case( DirContext.REPLACE_ATTRIBUTE ):
+                modOpObj = REPLACE_MODOP;
+                break;
+            default:
+                throw new IllegalArgumentException( "bad modification operation value: " + modOp );
+        }
+
+        stack.push( new Invocation( this, caller, "modify", new Object[] { name, modOpObj, mods }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().modify( name, modOp, mods );
@@ -218,12 +293,18 @@
         }
     }
 
-    public void modify(Name name, ModificationItem[] mods) throws NamingException {
+
+    public void modify( Name name, ModificationItem[] mods ) throws NamingException
+    {
+        modify( name, mods, null );
+    }
+
+
+    public void modify( Name name, ModificationItem[] mods, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "modify",
-                new Object[] { name, mods } ) );
+        stack.push( new Invocation( this, caller, "modify", new Object[] { name, mods }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().modify( name, mods );
@@ -234,12 +315,18 @@
         }
     }
 
-    public NamingEnumeration list(Name base) throws NamingException {
+
+    public NamingEnumeration list( Name base ) throws NamingException
+    {
+        return list( base, null );
+    }
+
+
+    public NamingEnumeration list( Name base, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "list",
-                new Object[] { base } ) );
+        stack.push( new Invocation( this, caller, "list", new Object[] { base }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().list( base );
@@ -250,12 +337,20 @@
         }
     }
 
-    public NamingEnumeration search(Name base, Map env, ExprNode filter, SearchControls searchCtls) throws NamingException {
+
+    public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls )
+            throws NamingException
+    {
+        return search( base, env, filter, searchCtls, null );
+    }
+
+
+    public NamingEnumeration search( Name base, Map env, ExprNode filter, SearchControls searchCtls, Collection bypass )
+            throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "search",
-                new Object[] { base, env, filter, searchCtls } ) );
+        stack.push( new Invocation( this, caller, "search", new Object[] { base, env, filter, searchCtls }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().search( base, env, filter, searchCtls );
@@ -266,12 +361,18 @@
         }
     }
 
-    public Attributes lookup(Name name) throws NamingException {
+
+    public Attributes lookup( Name name ) throws NamingException
+    {
+        return lookup( name, ( Collection ) null );
+    }
+
+
+    public Attributes lookup( Name name, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "lookup",
-                new Object[] { name } ) );
+        stack.push( new Invocation( this, caller, "lookup", new Object[] { name }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().lookup( name );
@@ -282,12 +383,18 @@
         }
     }
 
-    public Attributes lookup(Name dn, String[] attrIds) throws NamingException {
+
+    public Attributes lookup( Name dn, String[] attrIds ) throws NamingException
+    {
+        return lookup( dn, attrIds, null );
+    }
+
+
+    public Attributes lookup( Name dn, String[] attrIds, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "lookup",
-                new Object[] { dn, attrIds } ) );
+        stack.push( new Invocation( this, caller, "lookup", new Object[] { dn, attrIds }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().lookup( dn, attrIds );
@@ -298,12 +405,18 @@
         }
     }
 
-    public boolean hasEntry(Name name) throws NamingException {
+
+    public boolean hasEntry( Name name ) throws NamingException
+    {
+        return hasEntry( name, null );
+    }
+
+
+    public boolean hasEntry( Name name, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "hasEntry",
-                new Object[] { name } ) );
+        stack.push( new Invocation( this, caller, "hasEntry", new Object[] { name }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().hasEntry( name );
@@ -314,12 +427,18 @@
         }
     }
 
-    public boolean isSuffix(Name name) throws NamingException {
+
+    public boolean isSuffix( Name name ) throws NamingException
+    {
+        return isSuffix( name, null );
+    }
+
+
+    public boolean isSuffix( Name name, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "isSuffix",
-                new Object[] { name } ) );
+        stack.push( new Invocation( this, caller, "isSuffix", new Object[] { name }, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().isSuffix( name );
@@ -330,12 +449,19 @@
         }
     }
 
-    public void modifyRn(Name name, String newRn, boolean deleteOldRn) throws NamingException {
+
+    public void modifyRn( Name name, String newRn, boolean deleteOldRn ) throws NamingException
+    {
+        modifyRn( name, newRn, deleteOldRn, null );
+    }
+
+
+    public void modifyRn( Name name, String newRn, boolean deleteOldRn, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "modifyRn",
-                new Object[] { name, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE } ) );
+        Object[] args = new Object[] { name, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE };
+        stack.push( new Invocation( this, caller, "modifyRn", args, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().modifyRn( name, newRn, deleteOldRn );
@@ -346,12 +472,18 @@
         }
     }
 
-    public void move(Name oriChildName, Name newParentName) throws NamingException {
+
+    public void move( Name oriChildName, Name newParentName ) throws NamingException
+    {
+        move( oriChildName, newParentName, null );
+    }
+
+
+    public void move( Name oriChildName, Name newParentName, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "move",
-                new Object[] { oriChildName, newParentName } ) );
+        stack.push( new Invocation( this, caller, "move", new Object[] { oriChildName, newParentName }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().move( oriChildName, newParentName );
@@ -362,12 +494,20 @@
         }
     }
 
-    public void move(Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn) throws NamingException {
+
+    public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
+    {
+        move( oriChildName, newParentName, newRn, deleteOldRn, null );
+    }
+
+
+    public void move( Name oriChildName, Name newParentName, String newRn, boolean deleteOldRn, Collection bypass )
+            throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "move",
-                new Object[] { oriChildName, newParentName, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE } ) );
+        Object[] args = new Object[] { oriChildName, newParentName, newRn, deleteOldRn? Boolean.TRUE : Boolean.FALSE };
+        stack.push( new Invocation( this, caller, "move", args, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().move( oriChildName, newParentName, newRn, deleteOldRn );
@@ -378,11 +518,18 @@
         }
     }
 
+
     public Attributes getRootDSE() throws NamingException
     {
+        return getRootDSE( null );
+    }
+
+
+    public Attributes getRootDSE( Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation( caller, "getRootDSE" ) );
+        stack.push( new Invocation( this, caller, "getRootDSE", null, bypass ) );
         try
         {
             return this.configuration.getInterceptorChain().getRootDSE();
@@ -393,13 +540,18 @@
         }
     }
 
+
     public void addContextPartition( DirectoryPartitionConfiguration config ) throws NamingException
     {
+        addContextPartition( config, null );
+    }
+
+
+    public void addContextPartition( DirectoryPartitionConfiguration config, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "addContextPartition",
-                new Object[] { config } ) );
+        stack.push( new Invocation( this, caller, "addContextPartition", new Object[] { config }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().addContextPartition( config );
@@ -410,13 +562,18 @@
         }
     }
 
+
     public void removeContextPartition( Name suffix ) throws NamingException
     {
+        removeContextPartition( suffix, null );
+    }
+
+
+    public void removeContextPartition( Name suffix, Collection bypass ) throws NamingException
+    {
         ensureStarted();
         InvocationStack stack = InvocationStack.getInstance();
-        stack.push( new Invocation(
-                caller, "removeContextPartition",
-                new Object[] { suffix } ) );
+        stack.push( new Invocation( this, caller, "removeContextPartition", new Object[] { suffix }, bypass ) );
         try
         {
             this.configuration.getInterceptorChain().removeContextPartition( suffix );
@@ -427,7 +584,9 @@
         }
     }
 
-    private void ensureStarted() throws ServiceUnavailableException {
+
+    private void ensureStarted() throws ServiceUnavailableException
+    {
         if( !service.isStarted() )
         {
             throw new ServiceUnavailableException( "Directory service is not started." );
diff --git a/core/src/test/org/apache/ldap/server/jndi/RootDSETest.java b/core/src/test/org/apache/ldap/server/jndi/RootDSETest.java
index 615ad1a..987d10b 100644
--- a/core/src/test/org/apache/ldap/server/jndi/RootDSETest.java
+++ b/core/src/test/org/apache/ldap/server/jndi/RootDSETest.java
@@ -299,7 +299,7 @@
 
         try
         {
-            ctx.modifyAttributes( "", 0, null );
+            ctx.modifyAttributes( "", DirContext.ADD_ATTRIBUTE, null );
 
             fail( "we should never get here" );
         }