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 2010/07/16 17:27:19 UTC

svn commit: r964837 [2/2] - in /directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/subtree: SubentryCache.java SubentryInterceptor.java

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/subtree/SubentryInterceptor.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/subtree/SubentryInterceptor.java?rev=964837&r1=964836&r2=964837&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/subtree/SubentryInterceptor.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/subtree/SubentryInterceptor.java Fri Jul 16 15:27:19 2010
@@ -22,7 +22,6 @@ package org.apache.directory.server.core
 
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -133,7 +132,64 @@ public class SubentryInterceptor extends
     /** A reference to the SubtreeSpecification AT */
     private static AttributeType SUBTREE_SPECIFICATION_AT;
 
+    /** A reference to the AccessControlSubentries AT */
+    private static AttributeType ACCESS_CONTROL_SUBENTRIES_AT;
+    
+    /** A reference to the AccessControlSubentries AT */
+    private static AttributeType SUBSCHEMA_SUBENTRY_AT;
+
+    /** A reference to the CollectiveAttributeSubentries AT */
+    private static AttributeType COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT;
+
+    /** A reference to the TriggerExecutionSubentries AT */
+    private static AttributeType TRIGGER_EXECUTION_SUBENTRIES_AT;
+
+
+    //-------------------------------------------------------------------------------------------
+    // Search filter methods
+    //-------------------------------------------------------------------------------------------
+    /**
+     * SearchResultFilter used to filter out subentries based on objectClass values.
+     */
+    public class HideSubentriesFilter implements EntryFilter
+    {
+        public boolean accept( SearchingOperationContext searchContext, ClonedServerEntry entry ) throws Exception
+        {
+            // See if the requested entry is a subentry
+            if ( subentryCache.hasSubentry( entry.getDn() ) )
+            {
+                return false;
+            }
+
+            // see if we can use objectclass if present
+            return !entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC );
+        }
+    }
+
+
+    /**
+     * SearchResultFilter used to filter out normal entries but shows subentries based on 
+     * objectClass values.
+     */
+    public class HideEntriesFilter implements EntryFilter
+    {
+        public boolean accept( SearchingOperationContext searchContext, ClonedServerEntry entry ) throws Exception
+        {
+            // See if the requested entry is a subentry
+            if ( subentryCache.hasSubentry( entry.getDn() ) )
+            {
+                return true;
+            }
+
+            // see if we can use objectclass if present
+            return entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC );
+        }
+    }
 
+    
+    //-------------------------------------------------------------------------------------------
+    // Interceptor initialization
+    //-------------------------------------------------------------------------------------------
     /**
      * Initialize the Subentry Interceptor
      * 
@@ -150,6 +206,10 @@ public class SubentryInterceptor extends
         OBJECT_CLASS_AT = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
         ADMINISTRATIVE_ROLE_AT = schemaManager.getAttributeType( SchemaConstants.ADMINISTRATIVE_ROLE_AT );
         SUBTREE_SPECIFICATION_AT = schemaManager.getAttributeType( SchemaConstants.SUBTREE_SPECIFICATION_AT );
+        ACCESS_CONTROL_SUBENTRIES_AT = schemaManager.getAttributeType( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
+        SUBSCHEMA_SUBENTRY_AT = schemaManager.getAttributeType( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+        COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT = schemaManager.getAttributeType( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
+        TRIGGER_EXECUTION_SUBENTRIES_AT = schemaManager.getAttributeType( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
 
         ssParser = new SubtreeSpecificationParser( schemaManager );
         evaluator = new SubtreeEvaluator( schemaManager );
@@ -221,6 +281,12 @@ public class SubentryInterceptor extends
     }
 
 
+    //-------------------------------------------------------------------------------------------
+    // Helper methods
+    //-------------------------------------------------------------------------------------------
+    /**
+     * Return the list of AdministrativeRole for a subentry
+     */
     private Set<AdministrativeRole> getSubentryAdminRoles( Entry subentry ) throws LdapException
     {
         Set<AdministrativeRole> adminRoles = new HashSet<AdministrativeRole>();
@@ -256,49 +322,6 @@ public class SubentryInterceptor extends
     }
 
 
-    // -----------------------------------------------------------------------
-    // Methods/Code dealing with Subentry Visibility
-    // -----------------------------------------------------------------------
-
-    public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext )
-        throws LdapException
-    {
-        EntryFilteringCursor cursor = nextInterceptor.list( listContext );
-
-        if ( !isSubentryVisible( listContext ) )
-        {
-            cursor.addEntryFilter( new HideSubentriesFilter() );
-        }
-
-        return cursor;
-    }
-
-
-    public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext )
-        throws LdapException
-    {
-        EntryFilteringCursor cursor = nextInterceptor.search( searchContext );
-
-        // object scope searches by default return subentries
-        if ( searchContext.getScope() == SearchScope.OBJECT )
-        {
-            return cursor;
-        }
-
-        // for subtree and one level scope we filter
-        if ( !isSubentryVisible( searchContext ) )
-        {
-            cursor.addEntryFilter( new HideSubentriesFilter() );
-        }
-        else
-        {
-            cursor.addEntryFilter( new HideEntriesFilter() );
-        }
-
-        return cursor;
-    }
-
-
     /**
      * Checks to see if subentries for the search and list operations should be
      * made visible based on the availability of the search request control
@@ -318,463 +341,484 @@ public class SubentryInterceptor extends
         if ( opContext.hasRequestControl( SUBENTRY_CONTROL ) )
         {
             SubentriesControl subentriesControl = ( SubentriesControl ) opContext.getRequestControl( SUBENTRY_CONTROL );
+            
             return subentriesControl.isVisible();
         }
 
         return false;
     }
 
-
-    // -----------------------------------------------------------------------
-    // Methods dealing with entry and subentry addition
-    // -----------------------------------------------------------------------
-
     /**
-     * Evaluates the set of subentry subtrees upon an entry and returns the
-     * operational subentry attributes that will be added to the entry if
-     * added at the dn specified.
-     *
-     * @param dn the normalized distinguished name of the entry
-     * @param entryAttrs the entry attributes are generated for
-     * @return the set of subentry op attrs for an entry
-     * @throws Exception if there are problems accessing entry information
+     * Update all the entries under an AP adding the 
      */
-    public Entry getSubentryAttributes( DN dn, Entry entryAttrs ) throws LdapException
+    private void updateEntries( CoreSession session, DN apDn, SubtreeSpecification ss, DN baseDn, List<EntryAttribute> modifications  ) throws LdapException
     {
-        Entry subentryAttrs = new DefaultEntry( schemaManager, dn );
-        Iterator<String> list = subentryCache.nameIterator();
-
-        while ( list.hasNext() )
-        {
-            String subentryDnStr = list.next();
-            DN subentryDn = new DN( subentryDnStr );
-            subentryDn.normalize( schemaManager.getNormalizerMapping() );
-            DN apDn = subentryDn.getParent();
-            Subentry subentry = subentryCache.getSubentry( subentryDn );
-            SubtreeSpecification ss = subentry.getSubtreeSpecification();
-
-            if ( evaluator.evaluate( ss, apDn, dn, entryAttrs ) )
-            {
-                EntryAttribute operational;
+        ExprNode filter = new PresenceNode( OBJECT_CLASS_AT ); // (objectClass=*)
+        SearchControls controls = new SearchControls();
+        controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+        controls.setReturningAttributes( new String[]
+            { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
 
-                if ( subentry.isAccessControlAdminRole() )
-                {
-                    operational = subentryAttrs.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
+        SearchOperationContext searchOperationContext = new SearchOperationContext( session,
+            baseDn, filter, controls );
+        searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
 
-                    if ( operational == null )
-                    {
-                        operational = new DefaultEntryAttribute( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT,
-                            schemaManager.lookupAttributeTypeRegistry( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
-                        subentryAttrs.put( operational );
-                    }
+        EntryFilteringCursor subentries = nexus.search( searchOperationContext );
 
-                    operational.add( subentryDn.getNormName() );
-                }
+        try
+        {
+            while ( subentries.next() )
+            {
+                Entry candidate = subentries.get();
+                DN candidateDn = candidate.getDn();
                 
-                if ( subentry.isSchemaAdminRole() )
+                if ( evaluator.evaluate( ss, apDn, candidateDn, candidate ) )
                 {
-                    operational = subentryAttrs.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+                    nexus.modify( new ModifyOperationContext( session, candidateDn, 
+                        getOperationalModsForAdd(
+                        candidate, modifications ) ) );
+                }
+            }
+        }
+        catch ( Exception e )
+        {
+            throw new LdapOtherException( e.getMessage() );
+        }
+    }
 
-                    if ( operational == null )
-                    {
-                        operational = new DefaultEntryAttribute( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, schemaManager
-                            .lookupAttributeTypeRegistry( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
-                        subentryAttrs.put( operational );
-                    }
+    
+    /**
+     * Checks if the given DN is a namingContext
+     */
+    private boolean isNamingContext( DN dn ) throws LdapException
+    {
+        DN namingContext = nexus.findSuffix( dn );
+        
+        return dn.equals( namingContext );
+    }
+    
+    
+    /**
+     * Get the administrativePoint role
+     */
+    private void checkAdministrativeRole( OperationContext opContext, DN apDn ) throws LdapException
+    {
+        Entry administrationPoint = opContext.lookup( apDn, ByPassConstants.LOOKUP_BYPASS );
+        
+        // The administrativeRole AT must exist and not be null
+        EntryAttribute administrativeRole = administrationPoint.get( ADMINISTRATIVE_ROLE_AT );
 
-                    operational.add( subentryDn.getNormName() );
-                }
-                
-                if ( subentry.isCollectiveAdminRole() )
-                {
-                    operational = subentryAttrs.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
+        // check that administrativeRole has something valid in it for us
+        if ( ( administrativeRole == null ) || ( administrativeRole.size() <= 0 ) )
+        {
+            throw new LdapNoSuchAttributeException( I18n.err( I18n.ERR_306, apDn ) );
+        }
+    }
+    
+    
+    /**
+     * Get the SubtreeSpecification, parse it and stores it into the subentry
+     */
+    private void setSubtreeSpecification( Subentry subentry, Entry entry ) throws LdapException
+    {
+        String subtree = entry.get( SUBTREE_SPECIFICATION_AT ).getString();
+        SubtreeSpecification ss;
 
-                    if ( operational == null )
-                    {
-                        operational = new DefaultEntryAttribute( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT,
-                            schemaManager
-                                .lookupAttributeTypeRegistry( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
-                        subentryAttrs.put( operational );
-                    }
+        try
+        {
+            ss = ssParser.parse( subtree );
+        }
+        catch ( Exception e )
+        {
+            String msg = I18n.err( I18n.ERR_307, entry.getDn() );
+            LOG.warn( msg );
+            throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
+        }
+        
+        subentry.setSubtreeSpecification( ss );
+    }
+    
 
-                    operational.add( subentryDn.getNormName() );
-                }
-                
-                if ( subentry.isTriggersAdminRole() )
-                {
-                    operational = subentryAttrs.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
+    /**
+     * Checks to see if an entry being renamed has a descendant that is an
+     * administrative point.
+     *
+     * @param name the name of the entry which is used as the search base
+     * @return true if name is an administrative point or one of its descendants
+     * are, false otherwise
+     * @throws Exception if there are errors while searching the directory
+     */
+    private boolean hasAdministrativeDescendant( OperationContext opContext, DN name ) throws LdapException
+    {
+        ExprNode filter = new PresenceNode( ADMINISTRATIVE_ROLE_AT );
+        SearchControls controls = new SearchControls();
+        controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
 
-                    if ( operational == null )
-                    {
-                        operational = new DefaultEntryAttribute( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT,
-                            schemaManager.lookupAttributeTypeRegistry( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
-                        subentryAttrs.put( operational );
-                    }
+        SearchOperationContext searchOperationContext = new SearchOperationContext( opContext.getSession(), name,
+            filter, controls );
+        searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
 
-                    operational.add( subentryDn.getNormName() );
-                }
+        EntryFilteringCursor aps = nexus.search( searchOperationContext );
+
+        try
+        { 
+            if ( aps.next() )
+            {
+                aps.close();
+                return true;
             }
         }
+        catch ( Exception e )
+        {
+            throw new LdapOperationException( e.getMessage() );
+        }
+        
 
-        return subentryAttrs;
+        return false;
     }
 
 
-    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    private List<Modification> getModsOnEntryRdnChange( DN oldName, DN newName, Entry entry ) throws LdapException
     {
-        DN name = addContext.getDn();
-        ClonedServerEntry entry = addContext.getEntry();
+        List<Modification> modList = new ArrayList<Modification>();
 
-        if ( entry.contains(  OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
+        /*
+         * There are two different situations warranting action.  Firt if
+         * an ss evalutating to true with the old name no longer evalutates
+         * to true with the new name.  This would be caused by specific chop
+         * exclusions that effect the new name but did not effect the old
+         * name. In this case we must remove subentry operational attribute
+         * values associated with the dn of that subentry.
+         *
+         * In the second case an ss selects the entry with the new name when
+         * it did not previously with the old name.  Again this situation
+         * would be caused by chop exclusions. In this case we must add subentry
+         * operational attribute values with the dn of this subentry.
+         */
+        for ( DN subentryDn : subentryCache )
         {
-            // get the name of the administrative point and its administrativeRole attributes
-            DN apName = name.getParent();
-            Entry administrationPoint = addContext.lookup( apName, ByPassConstants.LOOKUP_BYPASS );
-            
-            // The administrativeRole AT must exist and not be null
-            EntryAttribute administrativeRole = administrationPoint.get( ADMINISTRATIVE_ROLE_AT );
+            DN apDn = subentryDn.getParent();
+            SubtreeSpecification ss = subentryCache.getSubentry( subentryDn ).getSubtreeSpecification();
+            boolean isOldNameSelected = evaluator.evaluate( ss, apDn, oldName, entry );
+            boolean isNewNameSelected = evaluator.evaluate( ss, apDn, newName, entry );
 
-            // check that administrativeRole has something valid in it for us
-            if ( ( administrativeRole == null ) || ( administrativeRole.size() <= 0 ) )
+            if ( isOldNameSelected == isNewNameSelected )
             {
-                throw new LdapNoSuchAttributeException( I18n.err( I18n.ERR_306, apName ) );
+                continue;
             }
 
-            /* ----------------------------------------------------------------
-             * Build the set of operational attributes to be injected into
-             * entries that are contained within the subtree represented by this
-             * new subentry.  In the process we make sure the proper roles are
-             * supported by the administrative point to allow the addition of
-             * this new subentry.
-             * ----------------------------------------------------------------
-             */
-            Subentry subentry = new Subentry();
-            subentry.setAdministrativeRoles( getSubentryAdminRoles( entry ) );
-            Entry operational = getSubentryOperationalAttributes( name, subentry );
-
-            /* ----------------------------------------------------------------
-             * Parse the subtreeSpecification of the subentry and add it to the
-             * SubtreeSpecification cache.  If the parse succeeds we continue
-             * to add the entry to the DIT.  Thereafter we search out entries
-             * to modify the subentry operational attributes of.
-             * ----------------------------------------------------------------
-             */
-            String subtree = entry.get( SUBTREE_SPECIFICATION_AT ).getString();
-            SubtreeSpecification ss;
-
-            try
-            {
-                ss = ssParser.parse( subtree );
-            }
-            catch ( Exception e )
+            // need to remove references to the subentry
+            if ( isOldNameSelected && !isNewNameSelected )
             {
-                String msg = I18n.err( I18n.ERR_307, name.getName() );
-                LOG.warn( msg );
-                throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg );
-            }
-            
-            subentry.setSubtreeSpecification( ss );
-
-            subentryCache.addSubentry( name, subentry );
-
-            next.add( addContext );
-
-            /* ----------------------------------------------------------------
-             * Find the baseDn for the subentry and use that to search the tree
-             * while testing each entry returned for inclusion within the
-             * subtree of the subentry's subtreeSpecification.  All included
-             * entries will have their operational attributes merged with the
-             * operational attributes calculated above.
-             * ----------------------------------------------------------------
-             */
-            DN baseDn = ( DN ) apName.clone();
-            baseDn.addAll( ss.getBase() );
-
-            /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-            ///   <Ugly-disgusting>
-            ///     We loop on *all* the entries under this subtree
-            ///     and we will add some operational attribute in each
-            ///     one of them. This is *utter crap* !!!
-            ///   </Ugly-disgusting>
-            /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-            /// What we should do :
-            ///   have a filter to process each entry when they are manipulated
-            /// instead of doing such a killing modification... This simply does 
-            /// not scale when we have more than a few hundred entries !
-            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT ); // (objectClass=*)
-            SearchControls controls = new SearchControls();
-            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-            controls.setReturningAttributes( new String[]
-                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
+                for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
+                {
+                    ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
+                    EntryAttribute opAttr = entry.get( aSUBENTRY_OPATTRS );
 
-            SearchOperationContext searchOperationContext = new SearchOperationContext( addContext.getSession(),
-                baseDn, filter, controls );
-            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+                    if ( opAttr != null )
+                    {
+                        opAttr = opAttr.clone();
+                        opAttr.remove( subentryDn.getNormName() );
 
-            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
+                        if ( opAttr.size() < 1 )
+                        {
+                            op = ModificationOperation.REMOVE_ATTRIBUTE;
+                        }
 
-            try
-            {
-                while ( subentries.next() )
-                {
-                    Entry candidate = subentries.get();
-                    DN candidateDn = candidate.getDn();
-                    
-                    if ( evaluator.evaluate( ss, apName, candidateDn, candidate ) )
-                    {
-                        nexus.modify( new ModifyOperationContext( addContext.getSession(), candidateDn, getOperationalModsForAdd(
-                            candidate, operational ) ) );
+                        modList.add( new DefaultModification( op, opAttr ) );
                     }
                 }
             }
-            catch ( Exception e )
+            // need to add references to the subentry
+            else if ( isNewNameSelected && !isOldNameSelected )
             {
-                throw new LdapOtherException( e.getMessage() );
+                for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
+                {
+                    ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
+                    EntryAttribute opAttr = new DefaultEntryAttribute( aSUBENTRY_OPATTRS, schemaManager
+                        .lookupAttributeTypeRegistry( aSUBENTRY_OPATTRS ) );
+                    opAttr.add( subentryDn.getNormName() );
+                    modList.add( new DefaultModification( op, opAttr ) );
+                }
             }
-
-            // TODO why are we doing this here if we got the entry from the 
-            // opContext in the first place - got to look into this 
-            addContext.setEntry( entry );
         }
-        else
-        {
-            Iterator<String> list = subentryCache.nameIterator();
 
-            while ( list.hasNext() )
-            {
-                String subentryDnStr = list.next();
-                DN subentryDn = new DN( subentryDnStr ).normalize( schemaManager.getNormalizerMapping() );
-                DN apDn = subentryDn.getParent();
-                Subentry subentry = subentryCache.getSubentry( subentryDn );
-                SubtreeSpecification ss = subentry.getSubtreeSpecification();
-
-                if ( evaluator.evaluate( ss, apDn, name, entry ) )
-                {
-                    EntryAttribute operational;
+        return modList;
+    }
 
-                    if ( subentry.isAccessControlAdminRole() )
-                    {
-                        operational = entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
 
-                        if ( operational == null )
-                        {
-                            operational = new DefaultEntryAttribute( schemaManager
-                                .lookupAttributeTypeRegistry( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
-                            entry.put( operational );
-                        }
-
-                        operational.add( subentryDn.getNormName() );
-                    }
+    // -----------------------------------------------------------------------
+    // Methods dealing with subentry modification
+    // -----------------------------------------------------------------------
 
-                    if ( subentry.isSchemaAdminRole() )
-                    {
-                        operational = entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
+    private Set<AdministrativeRole> getSubentryTypes( Entry entry, List<Modification> mods ) throws LdapException
+    {
+        EntryAttribute ocFinalState = entry.get( OBJECT_CLASS_AT ).clone();
 
-                        if ( operational == null )
+        for ( Modification mod : mods )
+        {
+            if ( mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT ) ||
+                 mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT_OID ) )
+            {
+                switch ( mod.getOperation() )
+                {
+                    case ADD_ATTRIBUTE:
+                        for ( Value<?> value : mod.getAttribute() )
                         {
-                            operational = new DefaultEntryAttribute( schemaManager
-                                .lookupAttributeTypeRegistry( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
-                            entry.put( operational );
+                            ocFinalState.add( value.getString() );
                         }
 
-                        operational.add( subentryDn.getNormName() );
-                    }
-
-                    if ( subentry.isCollectiveAdminRole() )
-                    {
-                        operational = entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
+                        break;
 
-                        if ( operational == null )
+                    case REMOVE_ATTRIBUTE:
+                        for ( Value<?> value : mod.getAttribute() )
                         {
-                            operational = new DefaultEntryAttribute( schemaManager
-                                .lookupAttributeTypeRegistry( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
-                            entry.put( operational );
+                            ocFinalState.remove( value.getString() );
                         }
 
-                        operational.add( subentryDn.getNormName() );
-                    }
-
-                    if ( subentry.isTriggersAdminRole() )
-                    {
-                        operational = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
-
-                        if ( operational == null )
-                        {
-                            operational = new DefaultEntryAttribute( schemaManager
-                                .lookupAttributeTypeRegistry( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
-                            entry.put( operational );
-                        }
+                        break;
 
-                        operational.add( subentryDn.getNormName() );
-                    }
+                    case REPLACE_ATTRIBUTE:
+                        ocFinalState = mod.getAttribute();
+                        break;
                 }
             }
-
-            // TODO why are we doing this here if we got the entry from the 
-            // opContext in the first place - got to look into this 
-            addContext.setEntry( entry );
-
-            next.add( addContext );
         }
+
+        Entry attrs = new DefaultEntry( schemaManager, DN.EMPTY_DN );
+        attrs.put( ocFinalState );
+        return getSubentryAdminRoles( attrs );
     }
 
 
     // -----------------------------------------------------------------------
-    // Methods dealing with subentry deletion
+    // Utility Methods
     // -----------------------------------------------------------------------
-    public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException
+
+    private List<Modification> getOperationalModsForReplace( DN oldName, DN newName, Subentry subentry, Entry entry )
+        throws Exception
     {
-        DN name = deleteContext.getDn();
-        Entry entry = deleteContext.getEntry();
+        List<Modification> modList = new ArrayList<Modification>();
 
-        // If the entry has a "subentry" Objectclass, we can process the entry.
-        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
+        EntryAttribute operational;
+
+        if ( subentry.isAccessControlAdminRole() )
         {
-            next.delete( deleteContext );
+            operational = entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ).clone();
 
-            Subentry removedSubentry = subentryCache.removeSubentry( name );
-            SubtreeSpecification ss = removedSubentry.getSubtreeSpecification();
+            if ( operational == null )
+            {
+                operational = new DefaultEntryAttribute( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, schemaManager
+                    .lookupAttributeTypeRegistry( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
+                operational.add( newName.toString() );
+            }
+            else
+            {
+                operational.remove( oldName.toString() );
+                operational.add( newName.toString() );
+            }
 
-            /* ----------------------------------------------------------------
-             * Find the baseDn for the subentry and use that to search the tree
-             * for all entries included by the subtreeSpecification.  Then we
-             * check the entry for subentry operational attribute that contain
-             * the DN of the subentry.  These are the subentry operational
-             * attributes we remove from the entry in a modify operation.
-             * ----------------------------------------------------------------
-             */
-            DN apName = name.getParent();
-            DN baseDn = ( DN ) apName.clone();
-            baseDn.addAll( ss.getBase() );
+            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
+        }
 
-            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
-            SearchControls controls = new SearchControls();
-            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-            controls.setReturningAttributes( new String[]
-                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
+        if ( subentry.isSchemaAdminRole() )
+        {
+            operational = entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).clone();
 
-            SearchOperationContext searchOperationContext = new SearchOperationContext( deleteContext.getSession(), baseDn,
-                filter, controls );
-            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+            if ( operational == null )
+            {
+                operational = new DefaultEntryAttribute( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, schemaManager
+                    .lookupAttributeTypeRegistry( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
+                operational.add( newName.toString() );
+            }
+            else
+            {
+                operational.remove( oldName.toString() );
+                operational.add( newName.toString() );
+            }
 
-            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
+            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
+        }
 
-            try
+        if ( subentry.isCollectiveAdminRole() )
+        {
+            operational = entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ).clone();
+
+            if ( operational == null )
             {
-                while ( subentries.next() )
-                {
-                    Entry candidate = subentries.get();
-                    DN candidateDn = candidate.getDn();
-    
-                    if ( evaluator.evaluate( ss, apName, candidateDn, candidate ) )
-                    {
-                        nexus.modify( new ModifyOperationContext( deleteContext.getSession(), candidateDn, getOperationalModsForRemove(
-                            name, candidate ) ) );
-                    }
-                }
-                
-                subentries.close();
+                operational = new DefaultEntryAttribute( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT,
+                    schemaManager.lookupAttributeTypeRegistry( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
+                operational.add( newName.toString() );
             }
-            catch ( Exception e )
+            else
             {
-                throw new LdapOperationException( e.getMessage() );
+                operational.remove( oldName.toString() );
+                operational.add( newName.toString() );
             }
+
+            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
         }
-        else
+
+        if ( subentry.isTriggersAdminRole() )
         {
-            next.delete( deleteContext );
+            operational = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ).clone();
+
+            if ( operational == null )
+            {
+                operational = new DefaultEntryAttribute( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT, schemaManager
+                    .lookupAttributeTypeRegistry( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
+                operational.add( newName.toString() );
+            }
+            else
+            {
+                operational.remove( oldName.toString() );
+                operational.add( newName.toString() );
+            }
+
+            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
         }
+
+        return modList;
     }
 
 
-    // -----------------------------------------------------------------------
-    // Methods dealing subentry name changes
-    // -----------------------------------------------------------------------
+    /**
+     * Gets the subschema operational attributes to be added to or removed from
+     * an entry selected by a subentry's subtreeSpecification.
+     */
+    private List<EntryAttribute> getSubentryOperationalAttributes( DN dn, Subentry subentry ) throws LdapException
+    {
+        List<EntryAttribute> attributes = new ArrayList<EntryAttribute>();
+
+        if ( subentry.isAccessControlAdminRole() )
+        {
+            EntryAttribute accessControlSubentries = new DefaultEntryAttribute( ACCESS_CONTROL_SUBENTRIES_AT, dn.getNormName() );
+            attributes.add( accessControlSubentries );
+        }
+        
+        if ( subentry.isSchemaAdminRole() )
+        {
+            EntryAttribute subschemaSubentry = new DefaultEntryAttribute( SUBSCHEMA_SUBENTRY_AT, dn.getNormName() );
+            attributes.add( subschemaSubentry );
+        }
+        
+        if ( subentry.isCollectiveAdminRole() )
+        {
+            EntryAttribute collectiveAttributeSubentries = new DefaultEntryAttribute( COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT, dn.getNormName() );
+            attributes.add( collectiveAttributeSubentries );
+        }
+        
+        if ( subentry.isTriggersAdminRole() )
+        {
+            EntryAttribute tiggerExecutionSubentries = new DefaultEntryAttribute( TRIGGER_EXECUTION_SUBENTRIES_AT, dn.getNormName() );
+            attributes.add( tiggerExecutionSubentries );
+        }
+
+        return attributes;
+    }
+
 
     /**
-     * Checks to see if an entry being renamed has a descendant that is an
-     * administrative point.
+     * Calculates the subentry operational attributes to remove from a candidate
+     * entry selected by a subtreeSpecification.  When we remove a subentry we
+     * must remove the operational attributes in the entries that were once selected
+     * by the subtree specification of that subentry.  To do so we must perform
+     * a modify operation with the set of modifications to perform.  This method
+     * calculates those modifications.
      *
-     * @param name the name of the entry which is used as the search base
-     * @return true if name is an administrative point or one of its descendants
-     * are, false otherwise
-     * @throws Exception if there are errors while searching the directory
+     * @param subentryDn the distinguished name of the subentry
+     * @param candidate the candidate entry to removed from the
+     * @return the set of modifications required to remove an entry's reference to
+     * a subentry
      */
-    private boolean hasAdministrativeDescendant( OperationContext opContext, DN name ) throws LdapException
+    private List<Modification> getOperationalModsForRemove( DN subentryDn, Entry candidate ) throws LdapException
     {
-        ExprNode filter = new PresenceNode( ADMINISTRATIVE_ROLE_AT );
-        SearchControls controls = new SearchControls();
-        controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-
-        SearchOperationContext searchOperationContext = new SearchOperationContext( opContext.getSession(), name,
-            filter, controls );
-        searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+        List<Modification> modList = new ArrayList<Modification>();
+        String dn = subentryDn.getNormName();
 
-        EntryFilteringCursor aps = nexus.search( searchOperationContext );
+        for ( String opAttrId : SUBENTRY_OPATTRS )
+        {
+            EntryAttribute opAttr = candidate.get( opAttrId );
 
-        try
-        { 
-            if ( aps.next() )
+            if ( ( opAttr != null ) && opAttr.contains( dn ) )
             {
-                aps.close();
-                return true;
+                AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( opAttrId );
+                EntryAttribute attr = new DefaultEntryAttribute( opAttrId, attributeType, dn );
+                modList.add( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr ) );
             }
         }
-        catch ( Exception e )
+
+        return modList;
+    }
+
+
+    /**
+     * Calculates the subentry operational attributes to add or replace from
+     * a candidate entry selected by a subtree specification.  When a subentry
+     * is added or it's specification is modified some entries must have new
+     * operational attributes added to it to point back to the associated
+     * subentry.  To do so a modify operation must be performed on entries
+     * selected by the subtree specification.  This method calculates the
+     * modify operation to be performed on the entry.
+     */
+    private List<Modification> getOperationalModsForAdd( Entry entry, List<EntryAttribute> operationalAttributes ) throws LdapException
+    {
+        List<Modification> modifications = new ArrayList<Modification>();
+
+        for ( EntryAttribute operationalAttribute : operationalAttributes )
         {
-            throw new LdapOperationException( e.getMessage() );
+            EntryAttribute opAttrInEntry = entry.get( operationalAttribute.getAttributeType() );
+            
+            if ( ( opAttrInEntry != null ) && ( opAttrInEntry.size() > 0 ) )
+            {
+                for ( Value<?> value : opAttrInEntry )
+                {                    
+                    operationalAttribute.add( value );
+                }
+                
+                modifications.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operationalAttribute ) );
+            }
+            else
+            {
+                modifications.add( new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, operationalAttribute ) );
+            }
         }
-        
 
-        return false;
+        return modifications;
     }
+    
 
-
-    private List<Modification> getModsOnEntryRdnChange( DN oldName, DN newName, Entry entry ) throws LdapException
+    /**
+     * Get the list of modification to apply to all the entries 
+     */
+    private List<Modification> getModsOnEntryModification( DN name, Entry oldEntry, Entry newEntry ) throws LdapException
     {
         List<Modification> modList = new ArrayList<Modification>();
 
-        /*
-         * There are two different situations warranting action.  Firt if
-         * an ss evalutating to true with the old name no longer evalutates
-         * to true with the new name.  This would be caused by specific chop
-         * exclusions that effect the new name but did not effect the old
-         * name. In this case we must remove subentry operational attribute
-         * values associated with the dn of that subentry.
-         *
-         * In the second case an ss selects the entry with the new name when
-         * it did not previously with the old name.  Again this situation
-         * would be caused by chop exclusions. In this case we must add subentry
-         * operational attribute values with the dn of this subentry.
-         */
-        Iterator<String> subentries = subentryCache.nameIterator();
-
-        while ( subentries.hasNext() )
+        for ( DN subentryDn : subentryCache )
         {
-            String subentryDnStr = subentries.next();
-            DN subentryDn = new DN( subentryDnStr ).normalize( schemaManager.getNormalizerMapping() );
             DN apDn = subentryDn.getParent();
             SubtreeSpecification ss = subentryCache.getSubentry( subentryDn ).getSubtreeSpecification();
-            boolean isOldNameSelected = evaluator.evaluate( ss, apDn, oldName, entry );
-            boolean isNewNameSelected = evaluator.evaluate( ss, apDn, newName, entry );
+            boolean isOldEntrySelected = evaluator.evaluate( ss, apDn, name, oldEntry );
+            boolean isNewEntrySelected = evaluator.evaluate( ss, apDn, name, newEntry );
 
-            if ( isOldNameSelected == isNewNameSelected )
+            if ( isOldEntrySelected == isNewEntrySelected )
             {
                 continue;
             }
 
             // need to remove references to the subentry
-            if ( isOldNameSelected && !isNewNameSelected )
+            if ( isOldEntrySelected && !isNewEntrySelected )
             {
                 for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
                 {
                     ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
-                    EntryAttribute opAttr = entry.get( aSUBENTRY_OPATTRS );
+                    EntryAttribute opAttr = oldEntry.get( aSUBENTRY_OPATTRS );
 
                     if ( opAttr != null )
                     {
                         opAttr = opAttr.clone();
-                        opAttr.remove( subentryDnStr );
+                        opAttr.remove( subentryDn.getNormName() );
 
                         if ( opAttr.size() < 1 )
                         {
@@ -786,214 +830,201 @@ public class SubentryInterceptor extends
                 }
             }
             // need to add references to the subentry
-            else if ( isNewNameSelected && !isOldNameSelected )
+            else if ( isNewEntrySelected && !isOldEntrySelected )
             {
-                for ( String aSUBENTRY_OPATTRS : SUBENTRY_OPATTRS )
+                for ( String attribute : SUBENTRY_OPATTRS )
                 {
                     ModificationOperation op = ModificationOperation.ADD_ATTRIBUTE;
-                    EntryAttribute opAttr = new DefaultEntryAttribute( aSUBENTRY_OPATTRS, schemaManager
-                        .lookupAttributeTypeRegistry( aSUBENTRY_OPATTRS ) );
-                    opAttr.add( subentryDnStr );
+                    AttributeType type = schemaManager.lookupAttributeTypeRegistry( attribute );
+                    EntryAttribute opAttr = new DefaultEntryAttribute( attribute, type );
+                    opAttr.add( subentryDn.getNormName() );
                     modList.add( new DefaultModification( op, opAttr ) );
                 }
             }
         }
 
-        return modList;
-    }
-
-
-    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
-    {
-        DN oldDn = renameContext.getDn();
-
-        Entry entry = renameContext.getEntry().getClonedEntry();
-
-        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
-        {
-            // @Todo To be reviewed !!!
-            Subentry subentry = subentryCache.removeSubentry( oldDn );
-            SubtreeSpecification ss = subentry.getSubtreeSpecification();
-            DN apName = oldDn.getParent();
-            DN baseDn = ( DN ) apName.clone();
-            baseDn.addAll( ss.getBase() );
-            DN newName = oldDn.getParent();
-
-            newName.add( renameContext.getNewRdn() );
-            newName.normalize( schemaManager.getNormalizerMapping() );
-
-            subentryCache.addSubentry( newName, subentry );
-            next.rename( renameContext );
-
-            subentry = subentryCache.getSubentry( newName );
-            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
-            SearchControls controls = new SearchControls();
-            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-            controls.setReturningAttributes( new String[]
-                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
-
-            SearchOperationContext searchOperationContext = new SearchOperationContext( renameContext.getSession(), baseDn,
-                filter, controls );
-            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
-
-            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
-
-            try
-            {
-                while ( subentries.next() )
-                {
-                    Entry candidate = subentries.get();
-                    DN dn = candidate.getDn();
-                    dn.normalize( schemaManager.getNormalizerMapping() );
-    
-                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
-                    {
-                        nexus.modify( new ModifyOperationContext( renameContext.getSession(), dn, getOperationalModsForReplace(
-                            oldDn, newName, subentry, candidate ) ) );
-                    }
-                }
-                
-                subentries.close();
-            }
-            catch ( Exception e )
-            {
-                throw new LdapOperationException( e.getMessage() );
-            }
-        }
-        else
+        return modList;
+    }
+
+    
+    //-------------------------------------------------------------------------------------------
+    // Interceptor API methods
+    //-------------------------------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException
+    {
+        DN dn = addContext.getDn();
+        ClonedServerEntry entry = addContext.getEntry();
+
+        // Check that the added entry is a subentry
+        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
         {
-            if ( hasAdministrativeDescendant( renameContext, oldDn ) )
+            // get the name of the administrative point and its administrativeRole attributes
+            // The AP must be the parent DN, but we also have to check that the given DN
+            // is not the rootDSE or a NamingContext
+            if ( dn.isRootDSE() || isNamingContext( dn ) )
             {
-                String msg = I18n.err( I18n.ERR_308 );
-                LOG.warn( msg );
-                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
+                // Not allowed : we can't get a parent in those cases
+                throw new LdapOtherException( "Cannot find an AdministrativePoint for " + dn );
             }
+            
+            // Get the administrativePoint role
+            DN apDn = dn.getParent();
+            checkAdministrativeRole( addContext, apDn );
 
-            next.rename( renameContext );
+            /* ----------------------------------------------------------------
+             * Build the set of operational attributes to be injected into
+             * entries that are contained within the subtree represented by this
+             * new subentry.  In the process we make sure the proper roles are
+             * supported by the administrative point to allow the addition of
+             * this new subentry.
+             * ----------------------------------------------------------------
+             */
+            Subentry subentry = new Subentry();
+            subentry.setAdministrativeRoles( getSubentryAdminRoles( entry ) );
+            List<EntryAttribute> operationalAttributes = getSubentryOperationalAttributes( dn, subentry );
 
-            // calculate the new DN now for use below to modify subentry operational
-            // attributes contained within this regular entry with name changes
-            DN newName = renameContext.getNewDn();
+            /* ----------------------------------------------------------------
+             * Parse the subtreeSpecification of the subentry and add it to the
+             * SubtreeSpecification cache.  If the parse succeeds we continue
+             * to add the entry to the DIT.  Thereafter we search out entries
+             * to modify the subentry operational attributes of.
+             * ----------------------------------------------------------------
+             */
+            setSubtreeSpecification( subentry, entry );
+            subentryCache.addSubentry( dn, subentry );
 
-            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newName, entry );
+            // Now inject the subentry into the backend
+            next.add( addContext );
 
-            if ( mods.size() > 0 )
-            {
-                nexus.modify( new ModifyOperationContext( renameContext.getSession(), newName, mods ) );
-            }
+            /* ----------------------------------------------------------------
+             * Find the baseDn for the subentry and use that to search the tree
+             * while testing each entry returned for inclusion within the
+             * subtree of the subentry's subtreeSpecification.  All included
+             * entries will have their operational attributes merged with the
+             * operational attributes calculated above.
+             * ----------------------------------------------------------------
+             */
+            DN baseDn = ( DN ) apDn.clone();
+            baseDn.addAll( subentry.getSubtreeSpecification().getBase() );
+            
+            updateEntries( addContext.getSession(), apDn, subentry.getSubtreeSpecification(), baseDn, operationalAttributes );
+
+            // TODO why are we doing this here if we got the entry from the 
+            // opContext in the first place - got to look into this 
+            addContext.setEntry( entry );
         }
-    }
+        else
+        {
+            // The added entry is not a Subentry
+            // Nevertheless, we have to check if the entry is added into an AdministrativePoint
+            // and is associated with a SubtreeSpecification
+            for ( DN subentryDn : subentryCache )
+            {
+                DN apDn = subentryDn.getParent();
+                Subentry subentry = subentryCache.getSubentry( subentryDn );
+                SubtreeSpecification ss = subentry.getSubtreeSpecification();
 
+                if ( evaluator.evaluate( ss, apDn, dn, entry ) )
+                {
+                    EntryAttribute operational;
 
-    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
-    {
-        DN oldDn = moveAndRenameContext.getDn();
-        DN newSuperiorDn = moveAndRenameContext.getNewSuperiorDn();
+                    if ( subentry.isAccessControlAdminRole() )
+                    {
+                        operational = entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT );
 
-        Entry entry = moveAndRenameContext.getOriginalEntry();
+                        if ( operational == null )
+                        {
+                            operational = new DefaultEntryAttribute( schemaManager
+                                .lookupAttributeTypeRegistry( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
+                            entry.put( operational );
+                        }
 
-        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
-        {
-            Subentry subentry = subentryCache.removeSubentry( oldDn );
-            SubtreeSpecification ss = subentry.getSubtreeSpecification();
-            DN apName = oldDn.getParent();
-            DN baseDn = ( DN ) apName.clone();
-            baseDn.addAll( ss.getBase() );
-            DN newName = newSuperiorDn.getParent();
+                        operational.add( subentryDn.getNormName() );
+                    }
 
-            newName.add( moveAndRenameContext.getNewRdn() );
-            newName.normalize( schemaManager.getNormalizerMapping() );
+                    if ( subentry.isSchemaAdminRole() )
+                    {
+                        operational = entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT );
 
-            subentryCache.addSubentry( newName, subentry );
-            
-            next.moveAndRename( moveAndRenameContext );
+                        if ( operational == null )
+                        {
+                            operational = new DefaultEntryAttribute( schemaManager
+                                .lookupAttributeTypeRegistry( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
+                            entry.put( operational );
+                        }
 
-            subentry = subentryCache.getSubentry( newName );
+                        operational.add( subentryDn.getNormName() );
+                    }
 
-            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
-            SearchControls controls = new SearchControls();
-            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
-            controls.setReturningAttributes( new String[]
-                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
+                    if ( subentry.isCollectiveAdminRole() )
+                    {
+                        operational = entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT );
 
-            SearchOperationContext searchOperationContext = new SearchOperationContext( moveAndRenameContext.getSession(), baseDn,
-                filter, controls );
-            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+                        if ( operational == null )
+                        {
+                            operational = new DefaultEntryAttribute( schemaManager
+                                .lookupAttributeTypeRegistry( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
+                            entry.put( operational );
+                        }
 
-            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
+                        operational.add( subentryDn.getNormName() );
+                    }
 
-            try
-            {
-                while ( subentries.next() )
-                {
-                    Entry candidate = subentries.get();
-                    DN dn = candidate.getDn();
-                    dn.normalize( schemaManager.getNormalizerMapping() );
-    
-                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
+                    if ( subentry.isTriggersAdminRole() )
                     {
-                        nexus.modify( new ModifyOperationContext( moveAndRenameContext.getSession(), dn, getOperationalModsForReplace(
-                            oldDn, newName, subentry, candidate ) ) );
+                        operational = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT );
+
+                        if ( operational == null )
+                        {
+                            operational = new DefaultEntryAttribute( schemaManager
+                                .lookupAttributeTypeRegistry( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
+                            entry.put( operational );
+                        }
+
+                        operational.add( subentryDn.getNormName() );
                     }
                 }
-                
-                subentries.close();
-            }
-            catch ( Exception e )
-            {
-                throw new LdapOperationException( e.getMessage() );
-            }
-        }
-        else
-        {
-            if ( hasAdministrativeDescendant( moveAndRenameContext, oldDn ) )
-            {
-                String msg = I18n.err( I18n.ERR_308 );
-                LOG.warn( msg );
-                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
             }
 
-            next.moveAndRename( moveAndRenameContext );
-
-            // calculate the new DN now for use below to modify subentry operational
-            // attributes contained within this regular entry with name changes
-            DN newDn = moveAndRenameContext.getNewDn();
-            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newDn, entry );
+            // TODO why are we doing this here if we got the entry from the 
+            // opContext in the first place - got to look into this 
+            addContext.setEntry( entry );
 
-            if ( mods.size() > 0 )
-            {
-                nexus.modify( new ModifyOperationContext( moveAndRenameContext.getSession(), newDn, mods ) );
-            }
+            next.add( addContext );
         }
     }
 
-
+    
     /**
      * {@inheritDoc}
      */
-    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
+    public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException
     {
-        DN oldDn = moveContext.getDn();
-        DN newSuperiorDn = moveContext.getNewSuperior();
-
-        Entry entry = moveContext.getOriginalEntry();
+        DN name = deleteContext.getDn();
+        Entry entry = deleteContext.getEntry();
 
+        // If the entry has a "subentry" Objectclass, we can process the entry.
         if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
         {
-            Subentry subentry = subentryCache.removeSubentry( oldDn );
-            SubtreeSpecification ss = subentry.getSubtreeSpecification();
-            DN apName = oldDn.getParent();
-            DN baseDn = ( DN ) apName.clone();
-            baseDn.addAll( ss.getBase() );
-            DN newName = (DN)newSuperiorDn.clone();
-            newName.add( oldDn.getRdn() );
-            newName.normalize( schemaManager.getNormalizerMapping() );
+            next.delete( deleteContext );
 
-            subentryCache.addSubentry( newName, subentry );
-            
-            next.move( moveContext );
+            Subentry removedSubentry = subentryCache.removeSubentry( name );
+            SubtreeSpecification ss = removedSubentry.getSubtreeSpecification();
 
-            subentry = subentryCache.getSubentry( newName );
+            /* ----------------------------------------------------------------
+             * Find the baseDn for the subentry and use that to search the tree
+             * for all entries included by the subtreeSpecification.  Then we
+             * check the entry for subentry operational attribute that contain
+             * the DN of the subentry.  These are the subentry operational
+             * attributes we remove from the entry in a modify operation.
+             * ----------------------------------------------------------------
+             */
+            DN apName = name.getParent();
+            DN baseDn = ( DN ) apName.clone();
+            baseDn.addAll( ss.getBase() );
 
             ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
             SearchControls controls = new SearchControls();
@@ -1001,7 +1032,7 @@ public class SubentryInterceptor extends
             controls.setReturningAttributes( new String[]
                 { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
 
-            SearchOperationContext searchOperationContext = new SearchOperationContext( moveContext.getSession(), baseDn,
+            SearchOperationContext searchOperationContext = new SearchOperationContext( deleteContext.getSession(), baseDn,
                 filter, controls );
             searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
 
@@ -1009,92 +1040,46 @@ public class SubentryInterceptor extends
 
             try
             {
-                // Modify all the entries under this subentry
                 while ( subentries.next() )
                 {
                     Entry candidate = subentries.get();
-                    DN dn = candidate.getDn();
-                    dn.normalize( schemaManager.getNormalizerMapping() );
+                    DN candidateDn = candidate.getDn();
     
-                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
+                    if ( evaluator.evaluate( ss, apName, candidateDn, candidate ) )
                     {
-                        nexus.modify( new ModifyOperationContext( moveContext.getSession(), dn, getOperationalModsForReplace(
-                            oldDn, newName, subentry, candidate ) ) );
-                    }
-                }
-                
-                subentries.close();
-            }
-            catch ( Exception e )
-            {
-                throw new LdapOperationException( e.getMessage() );
-            }
-        }
-        else
-        {
-            if ( hasAdministrativeDescendant( moveContext, oldDn ) )
-            {
-                String msg = I18n.err( I18n.ERR_308 );
-                LOG.warn( msg );
-                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
-            }
-
-            next.move( moveContext );
-
-            // calculate the new DN now for use below to modify subentry operational
-            // attributes contained within this regular entry with name changes
-            DN newName = moveContext.getNewDn();
-            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newName, entry );
-
-            if ( mods.size() > 0 )
+                        nexus.modify( new ModifyOperationContext( deleteContext.getSession(), candidateDn, getOperationalModsForRemove(
+                            name, candidate ) ) );
+                    }
+                }
+                
+                subentries.close();
+            }
+            catch ( Exception e )
             {
-                nexus.modify( new ModifyOperationContext( moveContext.getSession(), newName, mods ) );
+                throw new LdapOperationException( e.getMessage() );
             }
         }
+        else
+        {
+            next.delete( deleteContext );
+        }
     }
 
-
-    // -----------------------------------------------------------------------
-    // Methods dealing with subentry modification
-    // -----------------------------------------------------------------------
-
-    private Set<AdministrativeRole> getSubentryTypes( Entry entry, List<Modification> mods ) throws LdapException
+    
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext )
+        throws LdapException
     {
-        EntryAttribute ocFinalState = entry.get( OBJECT_CLASS_AT ).clone();
+        EntryFilteringCursor cursor = nextInterceptor.list( listContext );
 
-        for ( Modification mod : mods )
+        if ( !isSubentryVisible( listContext ) )
         {
-            if ( mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT ) ||
-                 mod.getAttribute().getId().equalsIgnoreCase( SchemaConstants.OBJECT_CLASS_AT_OID ) )
-            {
-                switch ( mod.getOperation() )
-                {
-                    case ADD_ATTRIBUTE:
-                        for ( Value<?> value : mod.getAttribute() )
-                        {
-                            ocFinalState.add( value.getString() );
-                        }
-
-                        break;
-
-                    case REMOVE_ATTRIBUTE:
-                        for ( Value<?> value : mod.getAttribute() )
-                        {
-                            ocFinalState.remove( value.getString() );
-                        }
-
-                        break;
-
-                    case REPLACE_ATTRIBUTE:
-                        ocFinalState = mod.getAttribute();
-                        break;
-                }
-            }
+            cursor.addEntryFilter( new HideSubentriesFilter() );
         }
 
-        Entry attrs = new DefaultEntry( schemaManager, DN.EMPTY_DN );
-        attrs.put( ocFinalState );
-        return getSubentryAdminRoles( attrs );
+        return cursor;
     }
 
 
@@ -1185,7 +1170,7 @@ public class SubentryInterceptor extends
 
             // search for all selected entries by the new SS and add references to subentry
             subentry = subentryCache.getSubentry( dn );
-            Entry operational = getSubentryOperationalAttributes( dn, subentry );
+            List<EntryAttribute> operationalAttributes = getSubentryOperationalAttributes( dn, subentry );
             DN newBaseDn = ( DN ) apName.clone();
             newBaseDn.addAll( ssNew.getBase() );
 
@@ -1204,7 +1189,7 @@ public class SubentryInterceptor extends
                     if ( evaluator.evaluate( ssNew, apName, candidateDn, candidate ) )
                     {
                         nexus.modify( new ModifyOperationContext( modifyContext.getSession(), candidateDn,
-                            getOperationalModsForAdd( candidate, operational ) ) );
+                            getOperationalModsForAdd( candidate, operationalAttributes ) ) );
                     }
                 }
             }
@@ -1232,338 +1217,366 @@ public class SubentryInterceptor extends
     }
 
 
-    // -----------------------------------------------------------------------
-    // Utility Methods
-    // -----------------------------------------------------------------------
-
-    private List<Modification> getOperationalModsForReplace( DN oldName, DN newName, Subentry subentry, Entry entry )
-        throws Exception
+    /**
+     * {@inheritDoc}
+     */
+    public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException
     {
-        List<Modification> modList = new ArrayList<Modification>();
+        DN oldDn = moveContext.getDn();
+        DN newSuperiorDn = moveContext.getNewSuperior();
 
-        EntryAttribute operational;
+        Entry entry = moveContext.getOriginalEntry();
 
-        if ( subentry.isAccessControlAdminRole() )
+        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
         {
-            operational = entry.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ).clone();
+            Subentry subentry = subentryCache.removeSubentry( oldDn );
+            SubtreeSpecification ss = subentry.getSubtreeSpecification();
+            DN apName = oldDn.getParent();
+            DN baseDn = ( DN ) apName.clone();
+            baseDn.addAll( ss.getBase() );
+            DN newName = (DN)newSuperiorDn.clone();
+            newName.add( oldDn.getRdn() );
+            newName.normalize( schemaManager.getNormalizerMapping() );
 
-            if ( operational == null )
-            {
-                operational = new DefaultEntryAttribute( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, schemaManager
-                    .lookupAttributeTypeRegistry( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) );
-                operational.add( newName.toString() );
-            }
-            else
-            {
-                operational.remove( oldName.toString() );
-                operational.add( newName.toString() );
-            }
+            subentryCache.addSubentry( newName, subentry );
+            
+            next.move( moveContext );
 
-            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
-        }
+            subentry = subentryCache.getSubentry( newName );
 
-        if ( subentry.isSchemaAdminRole() )
-        {
-            operational = entry.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).clone();
+            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+            controls.setReturningAttributes( new String[]
+                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
 
-            if ( operational == null )
+            SearchOperationContext searchOperationContext = new SearchOperationContext( moveContext.getSession(), baseDn,
+                filter, controls );
+            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+
+            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
+
+            try
             {
-                operational = new DefaultEntryAttribute( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, schemaManager
-                    .lookupAttributeTypeRegistry( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) );
-                operational.add( newName.toString() );
+                // Modify all the entries under this subentry
+                while ( subentries.next() )
+                {
+                    Entry candidate = subentries.get();
+                    DN dn = candidate.getDn();
+                    dn.normalize( schemaManager.getNormalizerMapping() );
+    
+                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
+                    {
+                        nexus.modify( new ModifyOperationContext( moveContext.getSession(), dn, getOperationalModsForReplace(
+                            oldDn, newName, subentry, candidate ) ) );
+                    }
+                }
+                
+                subentries.close();
             }
-            else
+            catch ( Exception e )
             {
-                operational.remove( oldName.toString() );
-                operational.add( newName.toString() );
+                throw new LdapOperationException( e.getMessage() );
             }
-
-            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
         }
-
-        if ( subentry.isCollectiveAdminRole() )
+        else
         {
-            operational = entry.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ).clone();
-
-            if ( operational == null )
-            {
-                operational = new DefaultEntryAttribute( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT,
-                    schemaManager.lookupAttributeTypeRegistry( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) );
-                operational.add( newName.toString() );
-            }
-            else
+            if ( hasAdministrativeDescendant( moveContext, oldDn ) )
             {
-                operational.remove( oldName.toString() );
-                operational.add( newName.toString() );
+                String msg = I18n.err( I18n.ERR_308 );
+                LOG.warn( msg );
+                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
             }
 
-            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
-        }
+            next.move( moveContext );
 
-        if ( subentry.isTriggersAdminRole() )
-        {
-            operational = entry.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ).clone();
+            // calculate the new DN now for use below to modify subentry operational
+            // attributes contained within this regular entry with name changes
+            DN newName = moveContext.getNewDn();
+            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newName, entry );
 
-            if ( operational == null )
-            {
-                operational = new DefaultEntryAttribute( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT, schemaManager
-                    .lookupAttributeTypeRegistry( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) );
-                operational.add( newName.toString() );
-            }
-            else
+            if ( mods.size() > 0 )
             {
-                operational.remove( oldName.toString() );
-                operational.add( newName.toString() );
+                nexus.modify( new ModifyOperationContext( moveContext.getSession(), newName, mods ) );
             }
-
-            modList.add( new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, operational ) );
         }
-
-        return modList;
     }
 
 
-    /**
-     * Gets the subschema operational attributes to be added to or removed from
-     * an entry selected by a subentry's subtreeSpecification.
-     *
-     * @param name the normalized distinguished name of the subentry (the value of op attrs)
-     * @param subentry the subentry to get attributes from
-     * @return the set of attributes to be added or removed from entries
-     */
-    private Entry getSubentryOperationalAttributes( DN name, Subentry subentry ) throws LdapException
+    public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
     {
-        Entry operational = new DefaultEntry( schemaManager, name );
+        DN oldDn = moveAndRenameContext.getDn();
+        DN newSuperiorDn = moveAndRenameContext.getNewSuperiorDn();
 
-        if ( subentry.isAccessControlAdminRole() )
-        {
-            if ( operational.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ) == null )
-            {
-                operational.put( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT, name.getNormName() );
-            }
-            else
-            {
-                operational.get( SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ).add( name.getNormName() );
-            }
-        }
-        
-        if ( subentry.isSchemaAdminRole() )
-        {
-            if ( operational.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ) == null )
-            {
-                operational.put( SchemaConstants.SUBSCHEMA_SUBENTRY_AT, name.getNormName() );
-            }
-            else
-            {
-                operational.get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).add( name.getNormName() );
-            }
-        }
-        
-        if ( subentry.isCollectiveAdminRole() )
+        Entry entry = moveAndRenameContext.getOriginalEntry();
+
+        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
         {
-            if ( operational.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ) == null )
+            Subentry subentry = subentryCache.removeSubentry( oldDn );
+            SubtreeSpecification ss = subentry.getSubtreeSpecification();
+            DN apName = oldDn.getParent();
+            DN baseDn = ( DN ) apName.clone();
+            baseDn.addAll( ss.getBase() );
+            DN newName = newSuperiorDn.getParent();
+
+            newName.add( moveAndRenameContext.getNewRdn() );
+            newName.normalize( schemaManager.getNormalizerMapping() );
+
+            subentryCache.addSubentry( newName, subentry );
+            
+            next.moveAndRename( moveAndRenameContext );
+
+            subentry = subentryCache.getSubentry( newName );
+
+            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+            controls.setReturningAttributes( new String[]
+                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
+
+            SearchOperationContext searchOperationContext = new SearchOperationContext( moveAndRenameContext.getSession(), baseDn,
+                filter, controls );
+            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
+
+            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
+
+            try
             {
-                operational.put( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT, name.getNormName() );
+                while ( subentries.next() )
+                {
+                    Entry candidate = subentries.get();
+                    DN dn = candidate.getDn();
+                    dn.normalize( schemaManager.getNormalizerMapping() );
+    
+                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
+                    {
+                        nexus.modify( new ModifyOperationContext( moveAndRenameContext.getSession(), dn, getOperationalModsForReplace(
+                            oldDn, newName, subentry, candidate ) ) );
+                    }
+                }
+                
+                subentries.close();
             }
-            else
+            catch ( Exception e )
             {
-                operational.get( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ).add( name.getNormName() );
+                throw new LdapOperationException( e.getMessage() );
             }
         }
-        
-        if ( subentry.isTriggersAdminRole() )
+        else
         {
-            if ( operational.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ) == null )
+            if ( hasAdministrativeDescendant( moveAndRenameContext, oldDn ) )
             {
-                operational.put( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT, name.getNormName() );
+                String msg = I18n.err( I18n.ERR_308 );
+                LOG.warn( msg );
+                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
             }
-            else
+
+            next.moveAndRename( moveAndRenameContext );
+
+            // calculate the new DN now for use below to modify subentry operational
+            // attributes contained within this regular entry with name changes
+            DN newDn = moveAndRenameContext.getNewDn();
+            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newDn, entry );
+
+            if ( mods.size() > 0 )
             {
-                operational.get( SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ).add( name.getNormName() );
+                nexus.modify( new ModifyOperationContext( moveAndRenameContext.getSession(), newDn, mods ) );
             }
         }
-
-        return operational;
     }
 
 
-    /**
-     * Calculates the subentry operational attributes to remove from a candidate
-     * entry selected by a subtreeSpecification.  When we remove a subentry we
-     * must remove the operational attributes in the entries that were once selected
-     * by the subtree specification of that subentry.  To do so we must perform
-     * a modify operation with the set of modifications to perform.  This method
-     * calculates those modifications.
-     *
-     * @param subentryDn the distinguished name of the subentry
-     * @param candidate the candidate entry to removed from the
-     * @return the set of modifications required to remove an entry's reference to
-     * a subentry
-     */
-    private List<Modification> getOperationalModsForRemove( DN subentryDn, Entry candidate ) throws LdapException
+    public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException
     {
-        List<Modification> modList = new ArrayList<Modification>();
-        String dn = subentryDn.getNormName();
+        DN oldDn = renameContext.getDn();
 
-        for ( String opAttrId : SUBENTRY_OPATTRS )
-        {
-            EntryAttribute opAttr = candidate.get( opAttrId );
+        Entry entry = renameContext.getEntry().getClonedEntry();
 
-            if ( ( opAttr != null ) && opAttr.contains( dn ) )
-            {
-                AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( opAttrId );
-                EntryAttribute attr = new DefaultEntryAttribute( opAttrId, attributeType, dn );
-                modList.add( new DefaultModification( ModificationOperation.REMOVE_ATTRIBUTE, attr ) );
-            }
-        }
+        if ( entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC ) )
+        {
+            // @Todo To be reviewed !!!
+            Subentry subentry = subentryCache.removeSubentry( oldDn );
+            SubtreeSpecification ss = subentry.getSubtreeSpecification();
+            DN apName = oldDn.getParent();
+            DN baseDn = ( DN ) apName.clone();
+            baseDn.addAll( ss.getBase() );
+            DN newName = oldDn.getParent();
 
-        return modList;
-    }
+            newName.add( renameContext.getNewRdn() );
+            newName.normalize( schemaManager.getNormalizerMapping() );
 
+            subentryCache.addSubentry( newName, subentry );
+            next.rename( renameContext );
 
-    /**
-     * Calculates the subentry operational attributes to add or replace from
-     * a candidate entry selected by a subtree specification.  When a subentry
-     * is added or it's specification is modified some entries must have new
-     * operational attributes added to it to point back to the associated
-     * subentry.  To do so a modify operation must be performed on entries
-     * selected by the subtree specification.  This method calculates the
-     * modify operation to be performed on the entry.
-     *
-     * @param entry the entry being modified
-     * @param operational the set of operational attributes supported by the AP
-     * of the subentry
-     * @return the set of modifications needed to update the entry
-     * @throws Exception if there are probelms accessing modification items
-     */
-    public List<Modification> getOperationalModsForAdd( Entry entry, Entry operational ) throws LdapException
-    {
-        List<Modification> modList = new ArrayList<Modification>();
+            subentry = subentryCache.getSubentry( newName );
+            ExprNode filter = new PresenceNode( OBJECT_CLASS_AT );
+            SearchControls controls = new SearchControls();
+            controls.setSearchScope( SearchControls.SUBTREE_SCOPE );
+            controls.setReturningAttributes( new String[]
+                { SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, SchemaConstants.ALL_USER_ATTRIBUTES } );
 
-        for ( AttributeType attributeType : operational.getAttributeTypes() )
-        {
-            ModificationOperation op = ModificationOperation.REPLACE_ATTRIBUTE;
-            EntryAttribute result = new DefaultEntryAttribute( attributeType );
-            EntryAttribute opAttrAdditions = operational.get( attributeType );
-            EntryAttribute opAttrInEntry = entry.get( attributeType );
+            SearchOperationContext searchOperationContext = new SearchOperationContext( renameContext.getSession(), baseDn,
+                filter, controls );
+            searchOperationContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
 
-            for ( Value<?> value : opAttrAdditions )
-            {
-                result.add( value );
-            }
+            EntryFilteringCursor subentries = nexus.search( searchOperationContext );
 
-            if ( opAttrInEntry != null && opAttrInEntry.size() > 0 )
+            try
             {
-                for ( Value<?> value : opAttrInEntry )
+                while ( subentries.next() )
                 {
-                    result.add( value );
+                    Entry candidate = subentries.get();
+                    DN dn = candidate.getDn();
+                    dn.normalize( schemaManager.getNormalizerMapping() );
+    
+                    if ( evaluator.evaluate( ss, apName, dn, candidate ) )
+                    {
+                        nexus.modify( new ModifyOperationContext( renameContext.getSession(), dn, getOperationalModsForReplace(
+                            oldDn, newName, subentry, candidate ) ) );
+                    }
                 }
+                
+                subentries.close();
             }
-            else
+            catch ( Exception e )
             {
-                op = ModificationOperation.ADD_ATTRIBUTE;
+                throw new LdapOperationException( e.getMessage() );
             }
-
-            modList.add( new DefaultModification( op, result ) );
         }
-
-        return modList;
-    }
-
-    /**
-     * SearchResultFilter used to filter out subentries based on objectClass values.
-     */
-    public class HideSubentriesFilter implements EntryFilter
-    {
-        public boolean accept( SearchingOperationContext searchContext, ClonedServerEntry entry ) throws Exception
+        else
         {
-            // see if we can get a match without normalization
-            if ( subentryCache.hasSubentry( entry.getDn() ) )
+            if ( hasAdministrativeDescendant( renameContext, oldDn ) )
             {
-                return false;
+                String msg = I18n.err( I18n.ERR_308 );
+                LOG.warn( msg );
+                throw new LdapSchemaViolationException( ResultCodeEnum.NOT_ALLOWED_ON_RDN, msg );
             }
 
-            // see if we can use objectclass if present
-            return !entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC );
+            next.rename( renameContext );
+
+            // calculate the new DN now for use below to modify subentry operational
+            // attributes contained within this regular entry with name changes
+            DN newName = renameContext.getNewDn();
+
+            List<Modification> mods = getModsOnEntryRdnChange( oldDn, newName, entry );
+
+            if ( mods.size() > 0 )
+            {
+                nexus.modify( new ModifyOperationContext( renameContext.getSession(), newName, mods ) );
+            }
         }
     }
 
+
     /**
-     * SearchResultFilter used to filter out normal entries but shows subentries based on 
-     * objectClass values.
+     * {@inheritDoc}
      */
-    public class HideEntriesFilter implements EntryFilter
+    public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext )
+        throws LdapException
     {
-        public boolean accept( SearchingOperationContext searchContext, ClonedServerEntry entry ) throws Exception
+        EntryFilteringCursor cursor = nextInterceptor.search( searchContext );
+
+        // object scope searches by default return subentries
+        if ( searchContext.getScope() == SearchScope.OBJECT )
         {
-            // see if we can get a match without normalization
-            if ( subentryCache.hasSubentry( entry.getDn() ) )
-            {
-                return true;
-            }
+            return cursor;
+        }
 
-            // see if we can use objectclass if present
-            return entry.contains( OBJECT_CLASS_AT, SchemaConstants.SUBENTRY_OC );

[... 137 lines stripped ...]