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 2008/10/07 13:27:01 UTC

svn commit: r702434 [3/5] - in /directory: apacheds/trunk/ apacheds/trunk/all/ apacheds/trunk/core-entry/src/main/java/org/apache/directory/server/core/entry/ apacheds/trunk/core-integ/src/main/java/org/apache/directory/server/core/integ/state/ apached...

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/CoreSession.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/CoreSession.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/CoreSession.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/CoreSession.java Tue Oct  7 04:26:55 2008
@@ -201,8 +201,6 @@
     // -----------------------------------------------------------------------
     // Operation Methods
     // -----------------------------------------------------------------------
-
-
     /**
      * Adds an entry into the DirectoryService associated with this CoreSession.
      * 
@@ -212,6 +210,25 @@
     void add( ServerEntry entry ) throws Exception;
     
     
+    /**
+     * Adds an entry into the DirectoryService associated with this CoreSession.
+     * The flag is used to tell the server to ignore the referrals and manipulate
+     * them as if they were normal entries.
+     * 
+     * @param entry the entry to add
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @exception Exception on failures to add the entry
+     */
+    void add( ServerEntry entry, boolean ignoreReferral ) throws Exception;
+    
+    
+    /**
+     * Adds an entry into the DirectoryService associated with this CoreSession.
+     * The entry is built using the received AddRequest.
+     * 
+     * @param AddRequest the request to execute
+     * @exception Exception on failures to add the entry
+     */
     void add( AddRequest addRequest ) throws Exception;
     
     
@@ -223,9 +240,29 @@
      * @param value the value to check for
      * @throws Exception if there are failures while comparing
      */
-    void compare( LdapDN dn, String oid, Object value ) throws Exception;
+    boolean compare( LdapDN dn, String oid, Object value ) throws Exception;
+    
+    
+    /**
+     * Checks to see if an attribute in an entry contains a value.
+     * The flag is used to tell the server to ignore the referrals and manipulate
+     * them as if they were normal entries.
+     *
+     * @param dn the distinguished name of the entry to check
+     * @param oid the OID of the attribute to check for the value
+     * @param value the value to check for
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @throws Exception if there are failures while comparing
+     */
+    boolean compare( LdapDN dn, String oid, Object value, boolean ignoreReferral ) throws Exception;
     
     
+    /**
+     * Checks to see if an attribute in an entry contains a value.
+     *
+     * @param compareRequest the received request
+     * @throws Exception if there are failures while comparing
+     */
     boolean compare( CompareRequest compareRequest ) throws Exception;
 
     
@@ -238,7 +275,20 @@
     void delete( LdapDN dn ) throws Exception;
     
     
+    /**
+     * Deletes an entry in the server.
+     * The flag is used to tell the server to ignore the referrals and manipulate
+     * them as if they were normal entries.
+     *
+     * @param dn the distinguished name of the entry to delete
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @throws Exception if there are failures while deleting the entry
+     */
+    void delete( LdapDN dn, boolean ignoreReferral ) throws Exception;
+    
+    
     void delete( DeleteRequest deleteRequest ) throws Exception;
+    
 
     /**
      * Checks to see if an entry exists. 
@@ -272,6 +322,20 @@
     void modify( LdapDN dn, List<Modification> mods ) throws Exception;
     
     
+    /**
+     * Modifies an entry within the server by applying a list of modifications 
+     * to the entry.
+     * The flag is used to tell the server to ignore the referrals and manipulate
+     * them as if they were normal entries.
+     *
+     * @param dn the distinguished name of the entry to modify
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @param mods the list of modifications to apply
+     * @throws Exception if there are failures while modifying the entry
+     */
+    void modify( LdapDN dn, List<Modification> mods, boolean ignoreReferral ) throws Exception;
+    
+    
     void modify( ModifyRequest modifyRequest ) throws Exception;
 
     
@@ -286,6 +350,24 @@
     void move( LdapDN dn, LdapDN newParent ) throws Exception;
     
     
+    /**
+     * Moves an entry or a branch of entries at a specified distinguished name
+     * to a position under a new parent.
+     * 
+     * @param dn the distinguished name of the entry/branch to move
+     * @param newParent the new parent under which the entry/branch is moved
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @exception if there are failures while moving the entry/branch
+     */
+    void move( LdapDN dn, LdapDN newParent, boolean ignoreReferral ) throws Exception;
+    
+    
+    /**
+     * Move an entry by changing its superior.
+     *
+     * @param modifyDnRequest The ModifyDN request
+     * @throws Exception if there are failures while moving the entry/branch
+     */
     void move( ModifyDnRequest modifyDnRequest ) throws Exception;
     
     
@@ -308,6 +390,29 @@
     void moveAndRename( LdapDN dn, LdapDN newParent, Rdn newRdn, boolean deleteOldRdn ) throws Exception;
     
     
+    /**
+     * Moves and renames (the relative distinguished name of) an entry (or a 
+     * branch if the entry has children) at a specified distinguished name to 
+     * a position under a new parent.
+     * 
+     * @param dn the distinguished name of the entry/branch to move
+     * @param newParent the new parent under which the entry/branch is moved
+     * @param newRdn the new relative distinguished name of the entry at the 
+     * root of the branch
+     * @param ignoreReferral  a flag to tell the server to ignore referrals
+     * @exception if there are failures while moving and renaming the entry
+     * or branch
+     */
+    void moveAndRename( LdapDN dn, LdapDN newParent, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) throws Exception;
+    
+    
+    /**
+     * Move and rename an entry. We change the RDN and the superior.
+     *
+     * @param modifyDnRequest The move and rename request
+     * @throws Exception if there are failures while moving and renaming the entry
+     * or branch
+     */
     void moveAndRename( ModifyDnRequest modifyDnRequest ) throws Exception;
     
     
@@ -330,6 +435,28 @@
     void rename( LdapDN dn, Rdn newRdn, boolean deleteOldRdn ) throws Exception;
     
     
+    /**
+     * Renames an entry by changing it's relative distinguished name.  This 
+     * has the side effect of changing the distinguished name of all entries
+     * directly or indirectly subordinate to the named entry if it has 
+     * descendants.
+     *
+     * @param dn the distinguished name of the entry to rename
+     * @param newRdn the new relative distinguished name for the entry
+     * @param deleteOldRdn whether or not the old value for the relative 
+     * distinguished name is to be deleted from the entry
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @throws Exception if there are failures while renaming the entry
+     */
+    void rename( LdapDN dn, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) throws Exception;
+    
+    
+    /**
+     * Rename an entry applying the ModifyDN request 
+     *
+     * @param modifyDnRequest The requested modification
+     * @throws Exception if there are failures while renaming the entry
+     */
     void rename( ModifyDnRequest modifyDnRequest ) throws Exception;
     
     
@@ -372,10 +499,36 @@
     
     
     /**
+     * Searches the directory using a specified filter. The scope is defaulting
+     * to 'base'. The alias dereferencing default to 'always'. the returned attributes 
+     * defaults to 'all the user attributes)
+     *
+     * @param dn the distinguished name of the entry to list the children of
+     * @param filter the search filter
+     * @throws Exception if there are failures while listing children
+     */
+    EntryFilteringCursor search( LdapDN dn, String filter ) throws Exception;
+    
+    
+    /**
+     * Searches the directory using a specified filter. The scope is defaulting
+     * to 'base'. The alias dereferencing default to 'always'. the returned attributes 
+     * defaults to 'all the user attributes)
+     *
+     * @param dn the distinguished name of the entry to list the children of
+     * @param filter the search filter
+     * @param ignoreReferrals a flag to tell the server to ignore referrals
+     * @throws Exception if there are failures while listing children
+     */
+    EntryFilteringCursor search( LdapDN dn, String filter, boolean ignoreReferrals ) throws Exception;
+    
+    
+    /**
      * Searches the directory using a specified search scope and filter.
      *
      * @param dn the distinguished name of the entry to list the children of
      * @param scope the search scope to apply
+     * @param filter the search filter
      * @param aliasDerefMode the alias dereferencing mode used
      * @param returningAttributes the attributes to return
      * @throws Exception if there are failures while listing children
@@ -388,6 +541,20 @@
      * Searches the directory using a specified search scope and filter.
      *
      * @param dn the distinguished name of the entry to list the children of
+     * @param scope the search scope to apply
+     * @param filter the search filter
+     * @param aliasDerefMode the alias dereferencing mode used
+     * @param returningAttributes the attributes to return
+     * @throws Exception if there are failures while listing children
+     */
+    //EntryFilteringCursor search( LdapDN dn, SearchScope scope, String filter, AliasDerefMode aliasDerefMode, 
+    //    String[] returningAttributes ) throws Exception;
+    
+    
+    /**
+     * Searches the directory using a specified search scope and filter.
+     *
+     * @param dn the distinguished name of the entry to list the children of
      * @param aliasDerefMode the alias dereferencing mode used
      * @param returningAttributes the attributes to return
      * @param sizeLimit the upper bound to the number of entries to return
@@ -399,6 +566,41 @@
         Set<AttributeTypeOptions> returningAttributes, int sizeLimit, int timeLimit ) throws Exception;
 
 
+    /**
+     * Searches the directory using a specified search scope and filter.
+     *
+     * @param dn the distinguished name of the entry to list the children of
+     * @param scope the search scope
+     * @param filter the search filter
+     * @param aliasDerefMode the alias dereferencing mode used
+     * @param returningAttributes the attributes to return
+     * @param sizeLimit the upper bound to the number of entries to return
+     * @param timeLimit the upper bound to the amount of time before 
+     * terminating the search
+     * @throws Exception if there are failures while listing children
+     */
+    //EntryFilteringCursor search( LdapDN dn, SearchScope scope, String filter, AliasDerefMode aliasDerefMode, 
+    //    String[] returningAttributes, int sizeLimit, int timeLimit ) throws Exception;
+
+
+    /**
+     * Searches the directory using a specified search scope and filter.
+     *
+     * @param dn the distinguished name of the entry to list the children of
+     * @param scope the search scope
+     * @param filter the search filter
+     * @param aliasDerefMode the alias dereferencing mode used
+     * @param returningAttributes the attributes to return
+     * @param sizeLimit the upper bound to the number of entries to return
+     * @param timeLimit the upper bound to the amount of time before 
+     * terminating the search
+     * @param ignoreReferral a flag to tell the server to ignore referrals
+     * @throws Exception if there are failures while listing children
+     */
+    //EntryFilteringCursor search( LdapDN dn, SearchScope scope, String filter, AliasDerefMode aliasDerefMode, 
+    //    String[] returningAttributes, int sizeLimit, int timeLimit, boolean ignoreReferral ) throws Exception;
+
+
     EntryFilteringCursor search( SearchRequest searchRequest ) throws Exception;
 
 

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java Tue Oct  7 04:26:55 2008
@@ -25,14 +25,18 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.naming.NamingException;
 import javax.naming.ldap.Control;
 
 import org.apache.directory.server.constants.ServerDNConstants;
 import org.apache.directory.server.core.authn.LdapPrincipal;
 import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.entry.ServerBinaryValue;
 import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.server.core.entry.ServerModification;
+import org.apache.directory.server.core.entry.ServerStringValue;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.interceptor.context.AbstractOperationContext;
 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
 import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
@@ -48,7 +52,9 @@
 import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
 import org.apache.directory.shared.ldap.entry.Modification;
+import org.apache.directory.shared.ldap.entry.Value;
 import org.apache.directory.shared.ldap.filter.ExprNode;
+import org.apache.directory.shared.ldap.filter.FilterParser;
 import org.apache.directory.shared.ldap.filter.SearchScope;
 import org.apache.directory.shared.ldap.message.AddRequest;
 import org.apache.directory.shared.ldap.message.AliasDerefMode;
@@ -60,7 +66,9 @@
 import org.apache.directory.shared.ldap.message.UnbindRequest;
 import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.directory.shared.ldap.name.Rdn;
+import org.apache.directory.shared.ldap.schema.AttributeType;
 import org.apache.directory.shared.ldap.schema.AttributeTypeOptions;
+import org.apache.directory.shared.ldap.util.StringTools;
 
 
 /**
@@ -86,30 +94,153 @@
     }
 
     
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#add(org.apache.directory.server.core.entry.ServerEntry)
+    /**
+     * Set the ignoreRefferal flag for the current operationContext.
+     *
+     * @param opContext The current operationContext
+     * @param ignoreReferral The flag 
+     */
+    private void setReferralHandling( AbstractOperationContext opContext, boolean ignoreReferral )
+    {
+        if ( ignoreReferral )
+        {
+            opContext.ignoreReferral();
+        }
+        else
+        {
+            opContext.throwReferral();
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc} 
      */
     public void add( ServerEntry entry ) throws Exception
     {
-        directoryService.getOperationManager().add( new AddOperationContext( this, entry ) );
+        AddOperationContext opContext = new AddOperationContext( this, entry );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.add( opContext );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#compare(org.apache.directory.shared.ldap.name.LdapDN, java.lang.String, java.lang.Object)
+    /**
+     * {@inheritDoc} 
      */
-    public void compare( LdapDN dn, String oid, Object value ) throws Exception
+    public void add( ServerEntry entry, boolean ignoreReferral ) throws Exception
     {
-        directoryService.getOperationManager().compare( new CompareOperationContext( this, dn, oid, value ) );
+        AddOperationContext opContext = new AddOperationContext( this, entry );
+        
+        setReferralHandling( opContext, ignoreReferral );
+        
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.add( opContext );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#delete(org.apache.directory.shared.ldap.name.LdapDN)
+    /**
+     * {@inheritDoc} 
+     */
+    public void add( AddRequest addRequest ) throws Exception
+    {
+        AddOperationContext opContext = new AddOperationContext( this, addRequest );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.add( opContext );
+        addRequest.getResultResponse().addAll( opContext.getResponseControls() );
+    }
+
+    
+    private Value<?> convertToValue( String oid, Object value ) throws NamingException
+    {
+        Value<?> val = null;
+        
+        AttributeType attributeType = directoryService.getRegistries().getAttributeTypeRegistry().lookup( oid );
+        
+        // make sure we add the request controls to operation
+        if ( attributeType.getSyntax().isHumanReadable() )
+        {
+            if ( value instanceof String )
+            {
+                val = new ServerStringValue( attributeType, (String)value );
+            }
+            else if ( value instanceof byte[] )
+            {
+                val = new ServerStringValue( attributeType, StringTools.utf8ToString( (byte[])value ) );
+            }
+            else
+            {
+                throw new NamingException( "Bad value for the OID " + oid );
+            }
+        }
+        else
+        {
+            if ( value instanceof String )
+            {
+                val = new ServerBinaryValue( attributeType, StringTools.getBytesUtf8( (String)value ) );
+            }
+            else if ( value instanceof byte[] )
+            {
+                val = new ServerBinaryValue( attributeType, (byte[])value );
+            }
+            else
+            {
+                throw new NamingException( "Bad value for the OID " + oid );
+            }
+        }
+        
+        return val;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( LdapDN dn, String oid, Object value ) throws Exception
+    {
+        OperationManager operationManager = directoryService.getOperationManager();
+        
+        return operationManager.compare( 
+            new CompareOperationContext( this, dn, oid, 
+                convertToValue( oid, value ) ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean compare( LdapDN dn, String oid, Object value, boolean ignoreReferral ) throws Exception
+    {
+        CompareOperationContext opContext =  
+                new CompareOperationContext( this, dn, oid, 
+                    convertToValue( oid, value ) );
+        
+        setReferralHandling( opContext, ignoreReferral );
+        
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.compare( opContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
      */
     public void delete( LdapDN dn ) throws Exception
     {
-        directoryService.getOperationManager().delete( new DeleteOperationContext( this, dn ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.delete( new DeleteOperationContext( this, dn ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void delete( LdapDN dn, boolean ignoreReferral  ) throws Exception
+    {
+        DeleteOperationContext opContext = new DeleteOperationContext( this, dn );
+        
+        setReferralHandling( opContext, ignoreReferral );
+
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.delete( opContext );
     }
 
 
@@ -255,7 +386,8 @@
     public EntryFilteringCursor list( LdapDN dn, AliasDerefMode aliasDerefMode,
         Set<AttributeTypeOptions> returningAttributes ) throws Exception
     {
-        return directoryService.getOperationManager().list( 
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.list( 
             new ListOperationContext( this, dn, aliasDerefMode, returningAttributes ) );
     }
 
@@ -269,7 +401,8 @@
         ListOperationContext opContext = new ListOperationContext( this, dn, aliasDerefMode, returningAttributes );
         opContext.setSizeLimit( sizeLimit );
         opContext.setTimeLimit( timeLimit );
-        return directoryService.getOperationManager().list( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.list( opContext );
     }
 
 
@@ -278,7 +411,8 @@
      */
     public ClonedServerEntry lookup( LdapDN dn ) throws Exception
     {
-        return directoryService.getOperationManager().lookup( new LookupOperationContext( this, dn ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.lookup( new LookupOperationContext( this, dn ) );
     }
 
 
@@ -287,13 +421,14 @@
      */
     public ClonedServerEntry lookup( LdapDN dn, String[] attrId ) throws Exception
     {
-        return directoryService.getOperationManager().lookup( 
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.lookup( 
             new LookupOperationContext( this, dn, attrId ) );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#modify(org.apache.directory.shared.ldap.name.LdapDN, java.util.List)
+    /**
+     * {@inheritDoc}
      */
     public void modify( LdapDN dn, List<Modification> mods ) throws Exception
     {
@@ -309,45 +444,149 @@
             serverModifications.add( new ServerModification( directoryService.getRegistries(), mod ) );
         }
         
-        directoryService.getOperationManager().modify( new ModifyOperationContext( this, dn, serverModifications ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.modify( new ModifyOperationContext( this, dn, serverModifications ) );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#move(org.apache.directory.shared.ldap.name.LdapDN, org.apache.directory.shared.ldap.name.LdapDN)
+    /**
+     * {@inheritDoc}
+     */
+    public void modify( LdapDN dn, List<Modification> mods, boolean ignoreReferral ) throws Exception
+    {
+        if ( mods == null )
+        {
+            return;
+        }
+        
+        List<Modification> serverModifications = new ArrayList<Modification>( mods.size() );
+        
+        for ( Modification mod:mods )
+        {
+            serverModifications.add( new ServerModification( directoryService.getRegistries(), mod ) );
+        }
+
+        ModifyOperationContext opContext = new ModifyOperationContext( this, dn, serverModifications );
+        
+        setReferralHandling( opContext, ignoreReferral );
+
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.modify( opContext );
+    }
+
+
+    /**
+     * {@inheritDoc} 
      */
     public void move( LdapDN dn, LdapDN newParent ) throws Exception
     {
-        directoryService.getOperationManager().move( new MoveOperationContext( this, dn, newParent ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.move( new MoveOperationContext( this, dn, newParent ) );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#moveAndRename(org.apache.directory.shared.ldap.name.LdapDN, org.apache.directory.shared.ldap.name.LdapDN, org.apache.directory.shared.ldap.name.Rdn, boolean)
+    /**
+     * {@inheritDoc} 
+     */
+    public void move( LdapDN dn, LdapDN newParent, boolean ignoreReferral ) throws Exception
+    {
+        OperationManager operationManager = directoryService.getOperationManager();
+        MoveOperationContext opContext = new MoveOperationContext( this, dn, newParent );
+        
+        setReferralHandling( opContext, ignoreReferral );
+
+        operationManager.move( opContext );
+    }
+
+
+    /**
+     * {@inheritDoc} 
      */
     public void moveAndRename( LdapDN dn, LdapDN newParent, Rdn newRdn, boolean deleteOldRdn ) throws Exception
     {
-        directoryService.getOperationManager().moveAndRename( 
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.moveAndRename( 
             new MoveAndRenameOperationContext( this, dn, newParent, newRdn, deleteOldRdn ) );
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.CoreSession#rename(org.apache.directory.shared.ldap.name.LdapDN, org.apache.directory.shared.ldap.name.Rdn, boolean)
+    /**
+     * {@inheritDoc} 
+     */
+    public void moveAndRename( LdapDN dn, LdapDN newParent, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) throws Exception
+    {
+        OperationManager operationManager = directoryService.getOperationManager();
+        MoveAndRenameOperationContext opContext = new MoveAndRenameOperationContext( this, dn, newParent, newRdn, deleteOldRdn );
+        
+        setReferralHandling( opContext, ignoreReferral );
+
+        operationManager.moveAndRename( opContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
      */
     public void rename( LdapDN dn, Rdn newRdn, boolean deleteOldRdn ) throws Exception
     {
-        directoryService.getOperationManager().rename( new RenameOperationContext( this, dn, newRdn, deleteOldRdn ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.rename( new RenameOperationContext( this, dn, newRdn, deleteOldRdn ) );
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    public void rename( LdapDN dn, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) throws Exception
+    {
+        OperationManager operationManager = directoryService.getOperationManager();
+        RenameOperationContext opContext = new RenameOperationContext( this, dn, newRdn, deleteOldRdn );
+        
+        setReferralHandling( opContext, ignoreReferral );
+
+        operationManager.rename( opContext );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( LdapDN dn, String filter ) throws Exception
+    {
+        return search( dn, filter, true );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntryFilteringCursor search( LdapDN dn, String filter, boolean ignoreReferrals ) throws Exception
+    {
+        OperationManager operationManager = directoryService.getOperationManager();
+        ExprNode filterNode = FilterParser.parse( filter ); 
+        
+        SearchOperationContext opContext = new SearchOperationContext( 
+            this, 
+            dn, 
+            SearchScope.OBJECT, 
+            filterNode, 
+            AliasDerefMode.DEREF_ALWAYS, 
+            null );
+        
+        setReferralHandling( opContext, ignoreReferrals );
+
+        return operationManager.search( opContext );
+    }
+    
+
     /* (non-Javadoc)
      * @see org.apache.directory.server.core.CoreSession#search(org.apache.directory.shared.ldap.name.LdapDN, org.apache.directory.shared.ldap.filter.SearchScope, org.apache.directory.shared.ldap.filter.ExprNode, org.apache.directory.shared.ldap.message.AliasDerefMode, java.util.Set)
      */
     public EntryFilteringCursor search( LdapDN dn, SearchScope scope, ExprNode filter, AliasDerefMode aliasDerefMode,
         Set<AttributeTypeOptions> returningAttributes ) throws Exception
     {
-        return directoryService.getOperationManager().search( new SearchOperationContext( this, dn, scope, filter, 
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.search( new SearchOperationContext( this, dn, scope, filter, 
             aliasDerefMode, returningAttributes ) );
     }
 
@@ -362,7 +601,8 @@
             aliasDerefMode, returningAttributes );
         opContext.setSizeLimit( sizeLimit );
         opContext.setTimeLimit( timeLimit );
-        return directoryService.getOperationManager().search( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.search( opContext );
     }
 
 
@@ -372,27 +612,27 @@
     }
 
 
-    public void add( AddRequest addRequest ) throws Exception
-    {
-        AddOperationContext opContext = new AddOperationContext( this, addRequest );
-        directoryService.getOperationManager().add( opContext );
-        addRequest.getResultResponse().addAll( opContext.getResponseControls() );
-    }
-
-
+    /**
+     * {@inheritDoc}
+     */
     public boolean compare( CompareRequest compareRequest ) throws Exception
     {
         CompareOperationContext opContext = new CompareOperationContext( this, compareRequest );
-        boolean result = directoryService.getOperationManager().compare( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        boolean result = operationManager.compare( opContext );
         compareRequest.getResultResponse().addAll( opContext.getResponseControls() );
         return result;
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
     public void delete( DeleteRequest deleteRequest ) throws Exception
     {
         DeleteOperationContext opContext = new DeleteOperationContext( this, deleteRequest );
-        directoryService.getOperationManager().delete( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.delete( opContext );
         deleteRequest.getResultResponse().addAll( opContext.getResponseControls() );
     }
 
@@ -402,45 +642,63 @@
     {
         LookupOperationContext opContext = new LookupOperationContext( this, dn );
         opContext.addRequestControls( requestControls );
-        return directoryService.getOperationManager().lookup( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.lookup( opContext );
     }
 
 
     public boolean exists( LdapDN dn ) throws Exception
     {
         EntryOperationContext opContext = new EntryOperationContext( this, dn );
-        return directoryService.getOperationManager().hasEntry( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        return operationManager.hasEntry( opContext );
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
     public void modify( ModifyRequest modifyRequest ) throws Exception
     {
         ModifyOperationContext opContext = new ModifyOperationContext( this, modifyRequest );
-        directoryService.getOperationManager().modify( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.modify( opContext );
         modifyRequest.getResultResponse().addAll( opContext.getResponseControls() );
     }
 
 
+    /**
+     * {@inheritDoc} 
+     */
     public void move( ModifyDnRequest modifyDnRequest ) throws Exception
     {
         MoveOperationContext opContext = new MoveOperationContext( this, modifyDnRequest );
-        directoryService.getOperationManager().move( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.move( opContext );
         modifyDnRequest.getResultResponse().addAll( opContext.getResponseControls() );
     }
 
 
+    /**
+     * {@inheritDoc} 
+     */
     public void moveAndRename( ModifyDnRequest modifyDnRequest ) throws Exception
     {
         MoveAndRenameOperationContext opContext = new MoveAndRenameOperationContext( this, modifyDnRequest );
-        directoryService.getOperationManager().moveAndRename( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.moveAndRename( opContext );
         modifyDnRequest.getResultResponse().addAll( opContext.getResponseControls() );
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
     public void rename( ModifyDnRequest modifyDnRequest ) throws Exception
     {
         RenameOperationContext opContext = new RenameOperationContext( this, modifyDnRequest );
-        directoryService.getOperationManager().rename( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.rename( opContext );
         modifyDnRequest.getResultResponse().addAll( opContext.getResponseControls() );
     }
 
@@ -448,7 +706,8 @@
     public EntryFilteringCursor search( SearchRequest searchRequest ) throws Exception
     {
         SearchOperationContext opContext = new SearchOperationContext( this, searchRequest );
-        EntryFilteringCursor cursor = directoryService.getOperationManager().search( opContext );
+        OperationManager operationManager = directoryService.getOperationManager();
+        EntryFilteringCursor cursor = operationManager.search( opContext );
         searchRequest.getResultResponse().addAll( opContext.getResponseControls() );
         return cursor;
     }
@@ -456,7 +715,8 @@
 
     public void unbind() throws Exception
     {
-        directoryService.getOperationManager().unbind( new UnbindOperationContext( this ) );
+        OperationManager operationManager = directoryService.getOperationManager();
+        operationManager.unbind( new UnbindOperationContext( this ) );
     }
 
 

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java Tue Oct  7 04:26:55 2008
@@ -55,6 +55,7 @@
 import org.apache.directory.server.xdbm.Index;
 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
+import org.apache.directory.server.core.referral.ReferralInterceptor;
 import org.apache.directory.server.core.schema.PartitionSchemaLoader;
 import org.apache.directory.server.core.schema.SchemaInterceptor;
 import org.apache.directory.server.core.schema.SchemaOperationControl;
@@ -562,6 +563,7 @@
 
         list.add( new NormalizationInterceptor() );
         list.add( new AuthenticationInterceptor() );
+        list.add( new ReferralInterceptor() );
         list.add( new AciAuthorizationInterceptor() );
         list.add( new DefaultAuthorizationInterceptor() );
         list.add( new ExceptionInterceptor() );
@@ -755,17 +757,17 @@
                     {
                         case( ChangeType.ADD_ORDINAL ):
                             adminSession.add( 
-                                new DefaultServerEntry( registries, reverse.getEntry() ) ); 
+                                new DefaultServerEntry( registries, reverse.getEntry() ), true ); 
                             break;
                             
                         case( ChangeType.DELETE_ORDINAL ):
-                            adminSession.delete( reverse.getDn() );
+                            adminSession.delete( reverse.getDn(), true );
                             break;
                             
                         case( ChangeType.MODIFY_ORDINAL ):
                             List<Modification> mods = reverse.getModificationItems();
     
-                            adminSession.modify( reverse.getDn(), mods );
+                            adminSession.modify( reverse.getDn(), mods, true );
                             break;
                             
                         case( ChangeType.MODDN_ORDINAL ):
@@ -891,6 +893,17 @@
     }
 
     /**
+     * Set the referralManager
+     * 
+     * @param referralManager The initialized referralManager
+     */
+    public void setReferralManager( ReferralManager referralManager )
+    {
+        this.referralManager = referralManager;
+    }
+    
+    
+    /**
      * @return the registries
      */
     public Registries getRegistries()
@@ -1399,9 +1412,6 @@
         interceptorChain = new InterceptorChain();
         interceptorChain.init( this );
 
-        // Initialize the referralManager
-        referralManager = new ReferralManagerImpl( this );
-        
         if ( changeLog.isEnabled() )
         {
             changeLog.init( this );

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DefaultOperationManager.java Tue Oct  7 04:26:55 2008
@@ -20,12 +20,19 @@
 package org.apache.directory.server.core;
 
 
-import java.util.Iterator;
-
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.NamingException;
+import javax.naming.PartialResultException;
+import javax.naming.ReferralException;
 import javax.naming.ServiceUnavailableException;
 
 import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
+import org.apache.directory.server.core.interceptor.InterceptorChain;
 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
 import org.apache.directory.server.core.interceptor.context.BindOperationContext;
 import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
@@ -45,7 +52,16 @@
 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
 import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
 import org.apache.directory.server.core.invocation.InvocationStack;
+import org.apache.directory.shared.ldap.codec.util.LdapURLEncodingException;
+import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.message.ResultCodeEnum;
 import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.shared.ldap.util.LdapURL;
+import org.apache.directory.shared.ldap.exception.LdapNamingException;
+import org.apache.directory.shared.ldap.exception.LdapReferralException;
+import org.apache.directory.shared.ldap.filter.SearchScope;
 
 
 /**
@@ -65,8 +81,125 @@
     }
     
     
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#add(org.apache.directory.server.core.interceptor.context.AddOperationContext)
+    private LdapReferralException buildReferralException( ServerEntry parentEntry, LdapDN childDn ) 
+        throws NamingException, LdapURLEncodingException
+    {
+        // Get the Ref attributeType
+        EntryAttribute refs = parentEntry.get( SchemaConstants.REF_AT );
+        
+        List<String> urls = new ArrayList<String>();
+        
+        // manage each Referral, building the correct URL for each of them
+        for ( Value<?> url:refs )
+        {
+            // we have to replace the parent by the referral
+            LdapURL ldapUrl = new LdapURL( (String)url.get() );
+            
+            // We have a problem with the DN : we can't use the UpName,
+            // as we may have some spaces around the ',' and '+'.
+            // So we have to take the RDN one by one, and create a 
+            // new DN with the type and value UP form
+            
+            LdapDN urlDn = (LdapDN)ldapUrl.getDn().addAll( childDn );
+            
+            ldapUrl.setDn( urlDn );
+            urls.add( ldapUrl.toString() );
+        }
+        
+        // Return with an exception
+        LdapReferralException lre = new LdapReferralException( urls );
+        lre.setRemainingName( childDn );
+        lre.setResolvedName( parentEntry.getDn() );
+        lre.setResolvedObj( parentEntry );
+        
+        return lre;
+    }
+    
+    
+    private LdapReferralException buildReferralExceptionForSearch( 
+        ServerEntry parentEntry, LdapDN childDn, SearchScope scope ) 
+    throws NamingException, LdapURLEncodingException
+{
+    // Get the Ref attributeType
+    EntryAttribute refs = parentEntry.get( SchemaConstants.REF_AT );
+    
+    List<String> urls = new ArrayList<String>();
+    
+    // manage each Referral, building the correct URL for each of them
+    for ( Value<?> url:refs )
+    {
+        // we have to replace the parent by the referral
+        try
+        {
+            LdapURL ldapUrl = new LdapURL( (String)url.get() );
+            
+            StringBuilder urlString = new StringBuilder();
+
+            if ( ( ldapUrl.getDn() == null ) || ( ldapUrl.getDn() == LdapDN.EMPTY_LDAPDN) )
+            {
+                ldapUrl.setDn( parentEntry.getDn() );
+            }
+            else
+            {
+                // We have a problem with the DN : we can't use the UpName,
+                // as we may have some spaces around the ',' and '+'.
+                // So we have to take the RDN one by one, and create a 
+                // new DN with the type and value UP form
+                
+                LdapDN urlDn = (LdapDN)ldapUrl.getDn().addAll( childDn );
+                
+                ldapUrl.setDn( urlDn );
+            }
+            
+            urlString.append( ldapUrl.toString() ).append( "??" );
+            
+            switch ( scope )
+            {
+                case OBJECT :
+                    urlString.append( "base" );
+                    break;
+                    
+                case SUBTREE :
+                    urlString.append( "sub" );
+                    break;
+                    
+                case ONELEVEL :
+                    urlString.append( "one" );
+                    break;
+            }
+            
+            urls.add( urlString.toString() );
+        }
+        catch ( LdapURLEncodingException luee )
+        {
+            // The URL is not correct, returns it as is
+            urls.add( (String)url.get() );
+        }
+    }
+    
+    // Return with an exception
+    LdapReferralException lre = new LdapReferralException( urls );
+    lre.setRemainingName( childDn );
+    lre.setResolvedName( parentEntry.getDn() );
+    lre.setResolvedObj( parentEntry );
+    
+    return lre;
+}
+
+
+    private PartialResultException buildPartialResultException( LdapDN childDn )
+    {
+        PartialResultException pre = new PartialResultException( "cannot create an entry under a referral when the Context.REFERRAL is set to 'ignore'" );
+        
+        pre.setRemainingName( childDn );
+        pre.setResolvedName( LdapDN.EMPTY_LDAPDN );
+        
+        return pre;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
      */
     public void add( AddOperationContext opContext ) throws Exception
     {
@@ -75,7 +208,45 @@
         
         try
         {
-            directoryService.getInterceptorChain().add( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+            {
+                ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+
+                // Depending on the Context.REFERRAL property value, we will throw
+                // a different exception.
+                if ( opContext.isReferralIgnored() )
+                {
+                    directoryService.getReferralManager().unlock();
+                    
+                    PartialResultException exception = buildPartialResultException( childDn );
+                    throw exception;
+                }
+                else
+                {
+                    // Unlock the referral manager
+                    directoryService.getReferralManager().unlock();
+                    
+                    ReferralException exception = buildReferralException( parentEntry, childDn );
+                    throw exception;
+                }
+            }
+            else
+            {
+                // Unlock the ReferralManager
+                directoryService.getReferralManager().unlock();
+
+                // Call the Add method
+                InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+                interceptorChain.add( opContext );
+            }
         }
         finally
         {
@@ -84,8 +255,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#bind(org.apache.directory.server.core.interceptor.context.BindOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void bind( BindOperationContext opContext ) throws Exception
     {
@@ -103,8 +274,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#compare(org.apache.directory.server.core.interceptor.context.CompareOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public boolean compare( CompareOperationContext opContext ) throws Exception
     {
@@ -113,7 +284,63 @@
         
         try
         {
-            return directoryService.getInterceptorChain().compare( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            return interceptorChain.compare( opContext );
         }
         finally
         {
@@ -122,8 +349,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#delete(org.apache.directory.server.core.interceptor.context.DeleteOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void delete( DeleteOperationContext opContext ) throws Exception
     {
@@ -132,7 +359,64 @@
         
         try
         {
-            directoryService.getInterceptorChain().delete( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't delete an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            interceptorChain.delete( opContext );
         }
         finally
         {
@@ -141,8 +425,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#getMatchedName(org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public LdapDN getMatchedName( GetMatchedNameOperationContext opContext ) throws Exception
     {
@@ -160,8 +444,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#getRootDSE(org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext ) 
         throws Exception
@@ -180,8 +464,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#getSuffix(org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public LdapDN getSuffix( GetSuffixOperationContext opContext ) throws Exception
     {
@@ -199,8 +483,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#hasEntry(org.apache.directory.server.core.interceptor.context.EntryOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public boolean hasEntry( EntryOperationContext opContext ) throws Exception
     {
@@ -218,8 +502,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#list(org.apache.directory.server.core.interceptor.context.ListOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
     {
@@ -237,10 +521,10 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#listSuffixes(org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext)
+    /**
+     * {@inheritDoc}
      */
-    public Iterator<String> listSuffixes( ListSuffixOperationContext opContext ) 
+    public Set<String> listSuffixes( ListSuffixOperationContext opContext ) 
         throws Exception
     {
         ensureStarted();
@@ -257,8 +541,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#lookup(org.apache.directory.server.core.interceptor.context.LookupOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
     {
@@ -276,8 +560,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#modify(org.apache.directory.server.core.interceptor.context.ModifyOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void modify( ModifyOperationContext opContext ) throws Exception
     {
@@ -286,7 +570,65 @@
         
         try
         {
-            directoryService.getInterceptorChain().modify( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't delete an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            interceptorChain.modify( opContext );
         }
         finally
         {
@@ -295,8 +637,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#move(org.apache.directory.server.core.interceptor.context.MoveOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void move( MoveOperationContext opContext ) throws Exception
     {
@@ -305,7 +647,84 @@
         
         try
         {
-            directoryService.getInterceptorChain().move( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't delete an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+            
+            // Now, check the destination
+            // Normalize the opContext DN
+            LdapDN parentDn = opContext.getParent();
+            parentDn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // If he parent DN is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result
+            // as stated by RFC 3296 Section 5.6.2
+            if ( directoryService.getReferralManager().isReferral( parentDn ) ||
+                 directoryService.getReferralManager().hasParentReferral( parentDn ) )
+            {
+                // Unlock the referral manager
+                directoryService.getReferralManager().unlock();
+
+                LdapNamingException exception = new LdapNamingException( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS );
+                exception.setRemainingName( dn );
+                
+                throw exception;
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            interceptorChain.move( opContext );
         }
         finally
         {
@@ -314,8 +733,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#moveAndRename(org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception
     {
@@ -324,7 +743,86 @@
         
         try
         {
-            directoryService.getInterceptorChain().moveAndRename( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't delete an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+            
+            // Now, check the destination
+            // Normalize the opContext DN
+            LdapDN parentDn = opContext.getParent();
+            parentDn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // If he parent DN is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result
+            // as stated by RFC 3296 Section 5.6.2
+            if ( directoryService.getReferralManager().isReferral( parentDn ) ||
+                 directoryService.getReferralManager().hasParentReferral( parentDn ) )
+            {
+                // Unlock the referral manager
+                directoryService.getReferralManager().unlock();
+
+                // The parent DN is a referral, we have to issue a AffectMultipleDsas result
+                // as stated by RFC 3296 Section 5.6.2
+                LdapNamingException exception = new LdapNamingException( ResultCodeEnum.AFFECTS_MULTIPLE_DSAS );
+                exception.setRemainingName( dn );
+                
+                throw exception;
+            }
+            
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            interceptorChain.moveAndRename( opContext );
         }
         finally
         {
@@ -333,8 +831,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#rename(org.apache.directory.server.core.interceptor.context.RenameOperationContext)
+    /**
+     * {@inheritDoc} 
      */
     public void rename( RenameOperationContext opContext ) throws Exception
     {
@@ -343,7 +841,65 @@
         
         try
         {
-            directoryService.getInterceptorChain().rename( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can delete it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't delete an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralException( parentEntry, childDn );
+                        throw exception;
+                    }
+                }
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            interceptorChain.rename( opContext );
         }
         finally
         {
@@ -352,8 +908,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#search(org.apache.directory.server.core.interceptor.context.SearchOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public EntryFilteringCursor search( SearchOperationContext opContext ) throws Exception
     {
@@ -362,7 +918,65 @@
         
         try
         {
-            return directoryService.getInterceptorChain().search( opContext );
+            // Normalize the opContext DN
+            LdapDN dn = opContext.getDn();
+            dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+
+            // We have to deal with the referral first
+            directoryService.getReferralManager().lockRead();
+
+            // Check if we have an ancestor for this DN
+            ServerEntry parentEntry = directoryService.getReferralManager().getParentReferral( dn );
+            
+            if ( parentEntry != null )
+            {
+                // We have found a parent referral for the current DN 
+                LdapDN childDn = (LdapDN)dn.getSuffix( parentEntry.getDn().size() );
+    
+                if ( directoryService.getReferralManager().isReferral( dn ) )
+                {
+                    // This is a referral. We can return it if the ManageDsaIt flag is true
+                    // Otherwise, we just throw a LdapReferralException
+                    if ( !opContext.isReferralIgnored() )
+                    {
+                        // Throw a Referral Exception
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralExceptionForSearch( parentEntry, childDn, opContext.getScope() );
+                        throw exception;
+                    }
+                }
+                else if ( directoryService.getReferralManager().hasParentReferral( dn ) )
+                {
+                    // We can't search an entry which has an ancestor referral
+    
+                    // Depending on the Context.REFERRAL property value, we will throw
+                    // a different exception.
+                    if ( opContext.isReferralIgnored() )
+                    {
+                        directoryService.getReferralManager().unlock();
+                        
+                        PartialResultException exception = buildPartialResultException( childDn );
+                        throw exception;
+                    }
+                    else
+                    {
+                        // Unlock the referral manager
+                        directoryService.getReferralManager().unlock();
+                        
+                        ReferralException exception = buildReferralExceptionForSearch( parentEntry, childDn, opContext.getScope() );
+                        throw exception;
+                    }
+                }
+            }
+
+            // Unlock the ReferralManager
+            directoryService.getReferralManager().unlock();
+
+            // Call the Add method
+            InterceptorChain interceptorChain = directoryService.getInterceptorChain();
+            return interceptorChain.search( opContext );
         }
         finally
         {
@@ -371,8 +985,8 @@
     }
 
 
-    /* (non-Javadoc)
-     * @see org.apache.directory.server.core.OperationManager#unbind(org.apache.directory.server.core.interceptor.context.UnbindOperationContext)
+    /**
+     * {@inheritDoc}
      */
     public void unbind( UnbindOperationContext opContext ) throws Exception
     {

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DirectoryService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DirectoryService.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DirectoryService.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/DirectoryService.java Tue Oct  7 04:26:55 2008
@@ -108,6 +108,14 @@
     ReferralManager getReferralManager();
 
     
+    /**
+     * Set the referralManager
+     * 
+     * @param referralManager The initialized referralManager
+     */
+    void setReferralManager( ReferralManager referralManager );
+
+    
     SchemaService getSchemaService();
 
 

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/OperationManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/OperationManager.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/OperationManager.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/OperationManager.java Tue Oct  7 04:26:55 2008
@@ -20,7 +20,7 @@
 package org.apache.directory.server.core;
 
 
-import java.util.Iterator;
+import java.util.Set;
 
 import org.apache.directory.server.core.entry.ClonedServerEntry;
 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
@@ -74,7 +74,7 @@
     /**
      * TODO document after determining if this method should be here.
      */
-    Iterator<String> listSuffixes( ListSuffixOperationContext opContext ) throws Exception;
+    Set<String> listSuffixes( ListSuffixOperationContext opContext ) throws Exception;
 
 
     /**

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManager.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManager.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManager.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManager.java Tue Oct  7 04:26:55 2008
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.server.core;
 
+import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.shared.ldap.name.LdapDN;
 
 /**
@@ -30,6 +31,30 @@
 public interface ReferralManager
 {
     /**
+     * Get a read-lock on the referralManager. 
+     * No read operation can be done on the referralManager if this
+     * method is not called before.
+     */
+    void lockRead();
+    
+    
+    /**
+     * Get a write-lock on the referralManager. 
+     * No write operation can be done on the referralManager if this
+     * method is not called before.
+     */
+    void lockWrite();
+    
+    
+    /**
+     * Release the read-write lock on the referralManager. 
+     * This method must be called after having read or modified the
+     * ReferralManager
+     */
+    void unlock();
+    
+    
+    /**
      * Tells if a DN is a referral (its associated entry contains the Referral ObjectClass).
      * 
      * It does not check that the associated entry inherits from a referral.
@@ -49,15 +74,24 @@
      * @param dn The DN we want to check for a referral in its partents
      * @return <code>true</code> if there is a parent referral
      */
-    boolean isParentReferral( LdapDN dn );
+    boolean hasParentReferral( LdapDN dn );
     
     
     /**
-     * Add a refrral to the manager.
+     * Get the DN of the parent referral for a specific DN
+     *
+     * @param dn The DN from which we want to get the parent referral
+     * @return The parent referral of null if none is found
+     */
+    ServerEntry getParentReferral( LdapDN dn );
+    
+    
+    /**
+     * Add a referral to the manager.
      *
      * @param dn The referral to add
      */
-    void addReferral( LdapDN dn );
+    void addReferral( ServerEntry entry );
     
     
     /**
@@ -65,7 +99,7 @@
      * 
      * @param dn The referral to remove
      */
-    void removeReferral( LdapDN dn );
+    void removeReferral( ServerEntry entry );
     
     
     /**
@@ -73,7 +107,20 @@
      * The manager will search for every entries having a Referral ObjectClass.
      *
      * @param directoryService The associated LDAP service
+     * @param suffixes The partition list
      * @exception If the initialization failed
      */
-    void init( DirectoryService directoryService ) throws Exception;
+    void init( DirectoryService directoryService, String... suffixes ) throws Exception;
+
+    
+    /**
+     * Remove a partition from the manager, reading all the referrals from the base.
+     * The manager will search for every entries having a Referral ObjectClass, and
+     * will remove them from the referrals table.
+     *
+     * @param directoryService The associated LDAP service
+     * @param suffixes The partition DN to remove
+     * @exception If the removal failed
+     */
+    void remove( DirectoryService directoryService, LdapDN suffix ) throws Exception;
 }

Modified: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java?rev=702434&r1=702433&r2=702434&view=diff
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java (original)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/ReferralManagerImpl.java Tue Oct  7 04:26:55 2008
@@ -19,7 +19,8 @@
  */
 package org.apache.directory.server.core;
 
-import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.naming.NamingException;
 import javax.naming.directory.SearchControls;
@@ -48,7 +49,10 @@
 public class ReferralManagerImpl implements ReferralManager
 {
     /** The referrals tree */
-    private DnBranchNode<LdapDN> referrals;
+    private DnBranchNode<ServerEntry> referrals;
+
+    /** A lock to guarantee the manager consistency */
+    private ReentrantReadWriteLock mutex = new ReentrantReadWriteLock();
 
     
     /**
@@ -60,25 +64,71 @@
      */
     public ReferralManagerImpl( DirectoryService directoryService ) throws Exception
     {
-        init( directoryService );
+        lockWrite();
+        
+        referrals = new DnBranchNode<ServerEntry>();
+        PartitionNexus nexus = directoryService.getPartitionNexus();
+
+        Set<String> suffixes = nexus.listSuffixes( null );
+        
+        init( directoryService, suffixes.toArray( new String[]{} ) );
+        
+        unlock();
+    }
+    
+    
+    /**
+     * Get a read-lock on the referralManager. 
+     * No read operation can be done on the referralManager if this
+     * method is not called before.
+     */
+    public void lockRead()
+    {
+        mutex.readLock().lock();
+    }
+    
+    
+    /**
+     * Get a write-lock on the referralManager. 
+     * No write operation can be done on the referralManager if this
+     * method is not called before.
+     */
+    public void lockWrite()
+    {
+        mutex.writeLock().lock();
+    }
+
+    
+    /**
+     * Release the read-write lock on the referralManager. 
+     * This method must be called after having read or modified the
+     * ReferralManager
+     */
+    public void unlock()
+    {
+        if ( mutex.isWriteLockedByCurrentThread() )
+        {
+            mutex.writeLock().unlock();
+        }
+        else
+        {
+            mutex.readLock().unlock();
+        }
     }
     
     
     /**
      * {@inheritDoc}
      */
-    public void addReferral( LdapDN dn )
+    public void addReferral( ServerEntry entry )
     {
-        synchronized ( referrals )
+        try
         {
-            try
-            {
-                ((DnBranchNode<LdapDN>)referrals).add( dn, dn );
-            }
-            catch ( NamingException ne )
-            {
-                // Do noghing
-            }
+            ((DnBranchNode<ServerEntry>)referrals).add( entry.getDn(), entry );
+        }
+        catch ( NamingException ne )
+        {
+            // Do nothing
         }
     }
 
@@ -86,9 +136,8 @@
     /**
      * {@inheritDoc}
      */
-    public void init( DirectoryService directoryService ) throws Exception
+    public void init( DirectoryService directoryService, String... suffixes ) throws Exception
     {
-        referrals = new DnBranchNode<LdapDN>();
         ExprNode referralFilter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT, 
             new ClientStringValue( SchemaConstants.REFERRAL_OC ) );
 
@@ -96,17 +145,15 @@
         SearchControls searchControl = new SearchControls();
         searchControl.setReturningObjFlag( false );
         searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
-        PartitionNexus nexus = directoryService.getPartitionNexus();
         
         CoreSession adminSession = directoryService.getAdminSession();
-        
-        Iterator<String> suffixes = nexus.listSuffixes( null );
+        PartitionNexus nexus = directoryService.getPartitionNexus();
 
-        while ( suffixes.hasNext() )
+        for ( String suffix:suffixes )
         {
             // We will store each entry's DN into the Referral tree
-            LdapDN suffix = new LdapDN( suffixes.next() );
-            EntryFilteringCursor cursor = nexus.search( new SearchOperationContext( adminSession, suffix, AliasDerefMode.DEREF_ALWAYS,
+            LdapDN suffixDn = new LdapDN( suffix );
+            EntryFilteringCursor cursor = nexus.search( new SearchOperationContext( adminSession, suffixDn, AliasDerefMode.DEREF_ALWAYS,
                 referralFilter, searchControl ) );
             
             // Move to the first entry in the cursor
@@ -115,9 +162,15 @@
             while ( cursor.next() ) 
             {
                 ServerEntry entry = cursor.get();
+
+                // Lock the referralManager
+                lockWrite();
                 
                 // Add it at the right place
-                addReferral( entry.getDn() );
+                addReferral( entry );
+                
+                // Unlock the referralManager
+                unlock();
             }
         }
     }
@@ -126,7 +179,40 @@
     /**
      * {@inheritDoc}
      */
-    public boolean isParentReferral( LdapDN dn )
+    public void remove( DirectoryService directoryService, LdapDN suffix ) throws Exception
+    {
+        ExprNode referralFilter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT, 
+            new ClientStringValue( SchemaConstants.REFERRAL_OC ) );
+
+        // Lookup for each entry with the ObjectClass = Referral value
+        SearchControls searchControl = new SearchControls();
+        searchControl.setReturningObjFlag( false );
+        searchControl.setSearchScope( SearchControls.SUBTREE_SCOPE );
+        
+        CoreSession adminSession = directoryService.getAdminSession();
+        PartitionNexus nexus = directoryService.getPartitionNexus();
+
+        // We will store each entry's DN into the Referral tree
+        EntryFilteringCursor cursor = nexus.search( new SearchOperationContext( adminSession, suffix, AliasDerefMode.DEREF_ALWAYS,
+            referralFilter, searchControl ) );
+        
+        // Move to the first entry in the cursor
+        cursor.beforeFirst();
+        
+        while ( cursor.next() ) 
+        {
+            ServerEntry entry = cursor.get();
+            
+            // Add it at the right place
+            removeReferral( entry );
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasParentReferral( LdapDN dn )
     {
         return referrals.hasParentElement( dn );
     }
@@ -135,19 +221,40 @@
     /**
      * {@inheritDoc}
      */
+    public ServerEntry getParentReferral( LdapDN dn )
+    {
+        if ( !hasParentReferral( dn ) )
+        {
+            return null;
+        }
+        
+        return referrals.getParentElement( dn );
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
     public boolean isReferral( LdapDN dn )
     {
-        LdapDN parent = referrals.getParentElement( dn );
+        ServerEntry parent = referrals.getParentElement( dn );
         
-        return dn.equals( parent );
+        if ( parent != null )
+        {
+            return dn.equals( parent.getDn() );
+        }
+        else
+        {
+            return false;
+        }
     }
 
 
     /**
      * {@inheritDoc}
      */
-    public void removeReferral( LdapDN dn )
+    public void removeReferral( ServerEntry entry )
     {
-        referrals.remove( dn );
+        referrals.remove( entry );
     }
 }