directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r910150 [2/11] - in /directory: apacheds/trunk/ apacheds/trunk/core-api/src/main/java/org/apache/directory/server/core/interceptor/context/ apacheds/trunk/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/messages/co...
Date Mon, 15 Feb 2010 01:37:47 GMT
Modified: directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java
URL: http://svn.apache.org/viewvc/directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java?rev=910150&r1=910149&r2=910150&view=diff
==============================================================================
--- directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java (original)
+++ directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapConnection.java Mon Feb 15 01:37:34 2010
@@ -32,7 +32,6 @@
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -42,18 +41,16 @@
 
 import org.apache.directory.ldap.client.api.exception.InvalidConnectionException;
 import org.apache.directory.ldap.client.api.exception.LdapException;
+import org.apache.directory.ldap.client.api.future.AddFuture;
 import org.apache.directory.ldap.client.api.future.BindFuture;
+import org.apache.directory.ldap.client.api.future.CompareFuture;
+import org.apache.directory.ldap.client.api.future.DeleteFuture;
+import org.apache.directory.ldap.client.api.future.ExtendedFuture;
+import org.apache.directory.ldap.client.api.future.ModifyDnFuture;
+import org.apache.directory.ldap.client.api.future.ModifyFuture;
 import org.apache.directory.ldap.client.api.future.ResponseFuture;
-import org.apache.directory.ldap.client.api.listener.AddListener;
-import org.apache.directory.ldap.client.api.listener.BindListener;
-import org.apache.directory.ldap.client.api.listener.CompareListener;
+import org.apache.directory.ldap.client.api.future.SearchFuture;
 import org.apache.directory.ldap.client.api.listener.DeleteListener;
-import org.apache.directory.ldap.client.api.listener.ExtendedListener;
-import org.apache.directory.ldap.client.api.listener.IntermediateResponseListener;
-import org.apache.directory.ldap.client.api.listener.ModifyDnListener;
-import org.apache.directory.ldap.client.api.listener.ModifyListener;
-import org.apache.directory.ldap.client.api.listener.OperationResponseListener;
-import org.apache.directory.ldap.client.api.listener.SearchListener;
 import org.apache.directory.ldap.client.api.message.AbandonRequest;
 import org.apache.directory.ldap.client.api.message.AbstractMessage;
 import org.apache.directory.ldap.client.api.message.AddRequest;
@@ -83,7 +80,6 @@
 import org.apache.directory.shared.asn1.ber.IAsn1Container;
 import org.apache.directory.shared.asn1.codec.DecoderException;
 import org.apache.directory.shared.asn1.primitives.OID;
-import org.apache.directory.shared.ldap.codec.LdapConstants;
 import org.apache.directory.shared.ldap.codec.LdapMessageCodec;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.LdapResultCodec;
@@ -140,11 +136,8 @@
 import org.apache.mina.core.future.WriteFuture;
 import org.apache.mina.core.service.IoConnector;
 import org.apache.mina.core.service.IoHandlerAdapter;
-import org.apache.mina.core.session.IoEventType;
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.filter.codec.ProtocolCodecFilter;
-import org.apache.mina.filter.executor.ExecutorFilter;
-import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
 import org.apache.mina.filter.ssl.SslFilter;
 import org.apache.mina.transport.socket.nio.NioSocketConnector;
 import org.slf4j.Logger;
@@ -154,6 +147,10 @@
 /**
  * This class is the base for every operations sent or received to and
  * from a LDAP server.
+ * 
+ * A connection instance is necessary to send requests to the server. The connection
+ * is valid until either the client closes it, the server closes it or the
+ * client does an unbind.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
@@ -190,11 +187,8 @@
     /** A Message ID which is incremented for each operation */
     private AtomicInteger messageId;
 
-    /** a map to hold the response listeners based on the operation id */
-    private Map<Integer, OperationResponseListener> listenerMap = new ConcurrentHashMap<Integer, OperationResponseListener>();
-
     /** a map to hold the ResponseFutures for all operations */
-    private Map<Integer, ResponseFuture> futureMap = new ConcurrentHashMap<Integer, ResponseFuture>();
+    private Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<Integer, ResponseFuture<? extends Response>>();
 
     /** a map to hold the response queues related to the operations */
     private Map<Integer, BlockingQueue<? extends Response>> respQueueMap = 
@@ -264,6 +258,35 @@
             throw new InvalidConnectionException( "Cannot connect on the server, the connection is invalid" );
         }
     }
+    
+    
+    private void addToFutureMap( int messageId, ResponseFuture<? extends Response> future )
+    {
+        //System.out.println( "Adding <" + messageId + ", " + future.getClass().getName() + ">" );
+        futureMap.put( messageId, future );
+    }
+    
+    
+    private ResponseFuture<? extends Response> getFromFutureMap( int messageId )
+    {
+        ResponseFuture<? extends Response> future = futureMap.remove( messageId );
+        
+        if ( future != null )
+        {
+            //System.out.println( "Removing <" + messageId + ", " + future.getClass().getName() + ">" );
+        }
+        
+        return future;
+    }
+
+
+    private ResponseFuture<? extends Response> peekFromFutureMap( int messageId )
+    {
+        ResponseFuture<? extends Response> future = futureMap.get( messageId );
+        //System.out.println( "Getting <" + messageId + ", " + future.getClass().getName() + ">" );
+        
+        return future;
+    }
 
 
     /**
@@ -443,7 +466,7 @@
         config.setUseSsl( false );
         config.setLdapPort( config.getDefaultLdapPort() );
         config.setLdapHost( config.getDefaultLdapHost() );
-        messageId = new AtomicInteger();
+        messageId = new AtomicInteger( 0 );
     }
 
 
@@ -456,7 +479,8 @@
     public LdapConnection( LdapConnectionConfig config )
     {
         this.config = config;
-        messageId = new AtomicInteger();
+        messageId = new AtomicInteger( 0 );
+        
     }
 
 
@@ -471,7 +495,7 @@
         config.setUseSsl( useSsl );
         config.setLdapPort( useSsl ? config.getDefaultLdapsPort() : config.getDefaultLdapPort() );
         config.setLdapHost( config.getDefaultLdapHost() );
-        messageId = new AtomicInteger();
+        messageId = new AtomicInteger( 0 );
     }
 
 
@@ -486,7 +510,7 @@
         config.setUseSsl( false );
         config.setLdapPort( config.getDefaultLdapPort() );
         config.setLdapHost( server );
-        messageId = new AtomicInteger();
+        messageId = new AtomicInteger( 0 );
     }
 
 
@@ -503,7 +527,7 @@
         config.setUseSsl( useSsl );
         config.setLdapPort( useSsl ? config.getDefaultLdapsPort() : config.getDefaultLdapPort() );
         config.setLdapHost( server );
-        messageId = new AtomicInteger();
+        messageId = new AtomicInteger( 0 );
     }
 
 
@@ -585,8 +609,8 @@
             // Add an executor so that this connection can be used
             // for handling more than one request (mainly because
             // we may have to handle some abandon request)
-            connector.getFilterChain().addLast( "executor",
-                new ExecutorFilter( new UnorderedThreadPoolExecutor( 10 ), IoEventType.MESSAGE_RECEIVED ) );
+            /*connector.getFilterChain().addLast( "executor",
+                new ExecutorFilter( new OrderedThreadPoolExecutor( 10 ), IoEventType.MESSAGE_RECEIVED ) );*/
 
             // Inject the protocolHandler
             connector.setHandler( this );
@@ -675,87 +699,141 @@
             throw new NullPointerException( msg );
         }
 
-        return add( new AddRequest( entry ), null );
+        return add( new AddRequest( entry ) );
+    }
+
+
+    /**
+     * Add an entry to the server asynchronously. This is a non blocking add : 
+     * the user has to get for the response from the returned Future.
+     * 
+     * @param entry The entry to add
+     * @result the add operation's Future 
+     */
+    public AddFuture addAsync( Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            String msg = "Cannot add empty entry";
+            LOG.debug( msg );
+            throw new NullPointerException( msg );
+        }
+
+        return addAsync( new AddRequest( entry ) );
     }
 
 
     /**
      * Add an entry present in the AddRequest to the server.
+     * 
      * @param addRequest the request object containing an entry and controls(if any)
      * @return the add operation's response
      * @throws LdapException
      */
     public AddResponse add( AddRequest addRequest ) throws LdapException
     {
-        return add( addRequest, null );
+        AddFuture addFuture = addAsync( addRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            long timeout = getTimeout( addRequest.getTimeout() );
+
+            // Get the response, blocking
+            AddResponse addResponse = ( AddResponse ) addFuture.get( timeout, TimeUnit.MILLISECONDS );
+            
+            if ( addResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Add failed : timeout occured" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+            
+            if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Add successful : {}", addResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Add failed : {}", addResponse );
+            }
+
+            return addResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !addFuture.isCancelled() )
+            {
+                abandon( addRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Add failed : timeout occured" );
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        catch ( Exception ie )
+        {
+            ie.printStackTrace();
+            
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+            LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
+            ldapException.initCause( ie );
+
+            // Send an abandon request
+            if ( !addFuture.isCancelled() )
+            {
+                abandon( addRequest.getMessageId() );
+            }
+
+            throw ldapException;
+        }
     }
 
 
     /**
      * Add an entry present in the AddRequest to the server.
+     * 
      * @param addRequest the request object containing an entry and controls(if any)
-     * @param listener A listener used for an asynchronous add operation
-     * @return the add operation's response, null if non-null listener is provided
+     * @return the add operation's response
      * @throws LdapException
      */
-    public AddResponse add( AddRequest addRequest, AddListener listener ) throws LdapException
+    public AddFuture addAsync( AddRequest addRequest ) throws LdapException
     {
         checkSession();
 
         AddRequestCodec addReqCodec = new AddRequestCodec();
 
         int newId = messageId.incrementAndGet();
-        LdapMessageCodec message = new LdapMessageCodec();
-        message.setMessageId( newId );
+        
+        addRequest.setMessageId( newId );
         addReqCodec.setMessageId( newId );
 
         addReqCodec.setEntry( addRequest.getEntry() );
         addReqCodec.setEntryDn( addRequest.getEntry().getDn() );
         setControls( addRequest.getControls(), addReqCodec );
 
-        message.setProtocolOP( addReqCodec );
-
-        BlockingQueue<Response> addResponseQueue = new LinkedBlockingQueue<Response>();
-        respQueueMap.put( newId, addResponseQueue );
-
-        ResponseFuture<Response> addFuture = new ResponseFuture<Response>( addResponseQueue );
-        futureMap.put( newId, addFuture );
+        AddFuture addFuture = new AddFuture( this, newId );
+        addToFutureMap( newId, addFuture );
 
         // Send the request to the server
-        ldapSession.write( message );
+        WriteFuture writeFuture = ldapSession.write( addReqCodec );
 
-        AddResponse response = null;
-        if ( listener == null )
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
         {
-            try
-            {
-                long timeout = getTimeout( addRequest.getTimeout() );
-                response = ( AddResponse ) addFuture.get( timeout, TimeUnit.MILLISECONDS );
+            // We didn't received anything : this is an error
+            LOG.error( "Add failed : timeout occured" );
 
-                if ( response == null )
-                {
-                    LOG.error( "Add failed : timeout occured" );
-                    throw new LdapException( TIME_OUT_ERROR );
-                }
-            }
-            catch ( InterruptedException ie )
-            {
-                LOG.error( OPERATION_CANCELLED, ie );
-                throw new LdapException( OPERATION_CANCELLED, ie );
-            }
-            catch ( Exception e )
-            {
-                LOG.error( NO_RESPONSE_ERROR );
-                removeFromMaps( newId );
-                throw new LdapException( NO_RESPONSE_ERROR, e );
-            }
-        }
-        else
-        {
-            listenerMap.put( newId, listener );
+            throw new LdapException( TIME_OUT_ERROR );
         }
-
-        return response;
+        
+        // Ok, done return the future
+        return addFuture;
     }
 
 
@@ -810,63 +888,48 @@
      */
     private void abandonInternal( AbandonRequest abandonRequest )
     {
-        // Create the new message and update the messageId
-        LdapMessageCodec message = new LdapMessageCodec();
+        // Create the inner abandonRequest
+        AbandonRequestCodec request = new AbandonRequestCodec();
 
-        // Creates the messageID and stores it into the 
-        // initial message and the transmitted message.
+        // Todo : The Abandon messageID is always 0
         int newId = messageId.incrementAndGet();
         abandonRequest.setMessageId( newId );
-        message.setMessageId( newId );
-
-        // Create the inner abandonRequest
-        AbandonRequestCodec request = new AbandonRequestCodec();
+        request.setMessageId( newId );
 
         // Inject the data into the request
         request.setAbandonedMessageId( abandonRequest.getAbandonedMessageId() );
 
-        // Inject the request into the message
-        message.setProtocolOP( request );
-
         // Inject the controls
-        setControls( abandonRequest.getControls(), message );
+        setControls( abandonRequest.getControls(), request );
 
         LOG.debug( "-----------------------------------------------------------------" );
-        LOG.debug( "Sending request \n{}", message );
+        LOG.debug( "Sending request \n{}", request );
 
         // Send the request to the server
-        ldapSession.write( message );
+        ldapSession.write( request );
 
         // remove the associated listener if any 
         int abandonId = abandonRequest.getAbandonedMessageId();
 
-        ResponseFuture rf = futureMap.remove( abandonId );
-        OperationResponseListener listener = listenerMap.remove( abandonId );
+        ResponseFuture rf = getFromFutureMap( abandonId );
 
         clearMaps();
         
         // if the listener is not null, this is a async operation and no need to
         // send cancel signal on future, sending so will leave a dangling poision object in the corresponding queue
-        if ( listener != null )
+        // this is a sync operation send cancel signal to the corresponding ResponseFuture
+        if ( rf != null )
         {
-            LOG.debug( "removed the listener associated with the abandoned operation with id {}", abandonId );
+            LOG.debug( "sending cancel signal to future" );
+            rf.cancel( true );
         }
         else
-        // this is a sync operation send cancel signal to the corresponding ResponseFuture
         {
-            if ( rf != null )
-            {
-                LOG.debug( "sending cancel signal to future" );
-                rf.cancel( true );
-            }
-            else
-            {
-                // this shouldn't happen
-                LOG
-                    .error(
-                        "There is no future asscoiated with operation message ID {}, perhaps the operation would have been completed",
-                        abandonId );
-            }
+            // this shouldn't happen
+            LOG
+                .error(
+                    "There is no future asscoiated with operation message ID {}, perhaps the operation would have been completed",
+                    abandonId );
         }
     }
 
@@ -885,13 +948,26 @@
 
 
     /**
+     * Anonymous asynchronous Bind on a server. 
+     *
+     * @return The BindFuture
+     */
+    public BindFuture bindAsync() throws LdapException, IOException
+    {
+        LOG.debug( "Anonymous Bind request" );
+
+        return bindAsync( StringTools.EMPTY, StringTools.EMPTY_BYTES );
+    }
+
+
+    /**
      * An Unauthenticated Authentication Bind on a server. (cf RFC 4513,
      * par 5.1.2)
      *
      * @param name The name we use to authenticate the user. It must be a 
      * valid DN
      * @return The BindResponse LdapResponse 
-     */
+     *
     public BindResponse bind( String name ) throws Exception
     {
         LOG.debug( "Bind request : {}", name );
@@ -901,26 +977,18 @@
 
 
     /**
-     * An Unauthenticated Authentication Bind on a server. (cf RFC 4513,
+     * An Unauthenticated Authentication asynchronous Bind on a server. (cf RFC 4513,
      * par 5.1.2)
      *
-     * @param name The name we use to authenticate the user.
-     * @return The BindResponse LdapResponse 
-     */
-    public BindResponse bind( LdapDN name ) throws Exception
+     * @param name The name we use to authenticate the user. It must be a 
+     * valid DN
+     * @return The BindFuture
+     *
+    public BindFuture bindAsync( String name ) throws Exception
     {
-        if ( name == null )
-        {
-            LOG.debug( "Anonymous Bind request : {}", name );
-
-            return bind( StringTools.EMPTY, StringTools.EMPTY_BYTES );
-        }
-        else
-        {
-            LOG.debug( "Unauthenticated Bind request : {}", name );
+        LOG.debug( "Bind request : {}", name );
 
-            return bind( name.getName(), StringTools.EMPTY_BYTES );
-        }
+        return bindAsync( name, StringTools.EMPTY_BYTES );
     }
 
 
@@ -941,6 +1009,22 @@
 
 
     /**
+     * Simple asynchronous Bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a 
+     * valid DN
+     * @param credentials The password. It can't be null 
+     * @return The BindResponse LdapResponse 
+     */
+    public BindFuture bindAsync( String name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        return bindAsync( name, StringTools.getBytesUtf8( credentials ) );
+    }
+
+
+    /**
      * Simple Bind on a server.
      *
      * @param name The name we use to authenticate the user. It must be a 
@@ -964,6 +1048,52 @@
 
 
     /**
+     * Simple asynchronous Bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a 
+     * valid DN
+     * @param credentials The password. It can't be null 
+     * @return The BindResponse LdapResponse 
+     */
+    public BindFuture bindAsync( LdapDN name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        if ( name == null )
+        {
+            return bindAsync( StringTools.EMPTY, StringTools.getBytesUtf8( credentials ) );
+        }
+        else
+        {
+            return bindAsync( name.getName(), StringTools.getBytesUtf8( credentials ) );
+        }
+    }
+
+
+    /**
+     * Simple asynchronous Bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a 
+     * valid DN
+     * @param credentials The password. It can't be null 
+     * @return The BindResponse LdapResponse 
+     */
+    public BindFuture bindAsync( LdapDN name, byte[] credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        if ( name == null )
+        {
+            return bindAsync( StringTools.EMPTY, credentials );
+        }
+        else
+        {
+            return bindAsync( name.getName(), credentials );
+        }
+    }
+
+
+    /**
      * Simple Bind on a server.
      *
      * @param name The name we use to authenticate the user.
@@ -974,7 +1104,14 @@
     {
         LOG.debug( "Bind request : {}", name );
 
-        return bind( name.getName(), credentials );
+        if ( name == null )
+        {
+            return bind( StringTools.EMPTY, credentials );
+        }
+        else
+        {
+            return bind( name.getName(), credentials );
+        }
     }
 
 
@@ -986,7 +1123,8 @@
      * @param credentials The password.
      * @return The BindResponse LdapResponse 
      */
-    public BindResponse bind( String name, byte[] credentials ) throws LdapException, IOException
+    public BindResponse bind( String name, byte[] credentials ) 
+        throws LdapException, IOException
     {
         LOG.debug( "Bind request : {}", name );
 
@@ -995,21 +1133,30 @@
         bindRequest.setName( name );
         bindRequest.setCredentials( credentials );
 
-        BindResponse response = bind( bindRequest );
+        return bind( bindRequest );
+    }
 
-        if ( LOG.isDebugEnabled() )
-        {
-            if ( response.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
-            {
-                LOG.debug( " Bind successfull" );
-            }
-            else
-            {
-                LOG.debug( " Bind failure {}", response );
-            }
-        }
 
-        return response;
+    /**
+     * Asynchronous Simple Bind on a server.
+     *
+     * @param name The name we use to authenticate the user. It must be a 
+     * valid DN
+     * @param credentials The password.
+     * @return The BindFuture 
+     */
+    public BindFuture bindAsync( String name, byte[] credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setName( name );
+        bindRequest.setCredentials( credentials );
+
+        BindFuture bindFuture = bindAsync( bindRequest );
+
+        return bindFuture;
     }
 
 
@@ -1022,7 +1169,7 @@
      */
     public BindResponse bind( BindRequest bindRequest ) throws LdapException, IOException
     {
-        BindFuture bindFuture = bind( bindRequest, null );
+        BindFuture bindFuture = bindAsync( bindRequest );
 
         // Get the result from the future
         try
@@ -1032,7 +1179,14 @@
 
             // Get the response, blocking
             BindResponse bindResponse = ( BindResponse ) bindFuture.get( timeout, TimeUnit.MILLISECONDS );
-
+            
+            if ( bindResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Bind failed : timeout occured" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+            
             if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
             {
                 authenticated = true;
@@ -1078,40 +1232,116 @@
             throw ldapException;
         }
     }
-
-
+    
+    
     /**
-     * Create a LdapMessage ready to be sent.
+     * Create a SearchRequestCodec ready to be sent.
      */
-    private LdapMessageCodec createBindMessage( BindRequest bindRequest ) throws LdapException
+    private SearchRequestCodec createSearchMessage( SearchRequest searchRequest ) throws LdapException
     {
-        LdapMessageCodec bindMessage = new LdapMessageCodec();
+        // Create a new codec SearchRequest object
+        SearchRequestCodec request = new SearchRequestCodec();
 
         // Creates the messageID and stores it into the 
         // initial message and the transmitted message.
-        // As it's a Bind request, reset the MessageId 
-        // value to zero.
-        messageId.set( 0 );
-
-        // clear the mappings if any (in case of a second call to bind() without calling unBind())
-        clearMaps();
-        
-        // the bind request should always start with message id 1 (One)
         int newId = messageId.incrementAndGet();
-        bindRequest.setMessageId( newId );
-        bindMessage.setMessageId( newId );
-
-        // Create a new codec BindRequest object
-        BindRequestCodec request = new BindRequestCodec();
-
-        // Set the version
-        request.setVersion( LdapConnectionConfig.LDAP_V3 );
+        searchRequest.setMessageId( newId );
+        request.setMessageId( newId );
 
         // Set the name
         try
         {
-            LdapDN dn = new LdapDN( bindRequest.getName() );
-            request.setName( dn );
+            LdapDN dn = new LdapDN( searchRequest.getBaseDn() );
+            request.setBaseObject( dn );
+        }
+        catch ( InvalidNameException ine )
+        {
+            String msg = "The given dn '" + searchRequest.getBaseDn() + "' is not valid";
+            LOG.error( msg );
+            LdapException ldapException = new LdapException( msg );
+            ldapException.initCause( ine );
+
+            throw ldapException;
+        }
+
+        // Set the scope
+        request.setScope( searchRequest.getScope() );
+
+        // Set the typesOnly flag
+        request.setDerefAliases( searchRequest.getDerefAliases().getValue() );
+
+        // Set the timeLimit
+        request.setTimeLimit( searchRequest.getTimeLimit() );
+
+        // Set the sizeLimit
+        request.setSizeLimit( searchRequest.getSizeLimit() );
+
+        // Set the typesOnly flag
+        request.setTypesOnly( searchRequest.getTypesOnly() );
+
+        // Set the filter
+        Filter filter = null;
+
+        try
+        {
+            ExprNode filterNode = FilterParser.parse( searchRequest.getFilter() );
+
+            filter = LdapTransformer.transformFilter( filterNode );
+        }
+        catch ( ParseException pe )
+        {
+            String msg = "The given filter '" + searchRequest.getFilter() + "' is not valid";
+            LOG.error( msg );
+            LdapException ldapException = new LdapException( msg );
+            ldapException.initCause( pe );
+
+            throw ldapException;
+        }
+
+        request.setFilter( filter );
+
+        // Set the attributes
+        Set<String> attributes = searchRequest.getAttributes();
+
+        if ( attributes != null )
+        {
+            for ( String attribute : attributes )
+            {
+                request.addAttribute( attribute );
+            }
+        }
+
+        // Add the controls
+        setControls( searchRequest.getControls(), request );
+
+        return request;
+    }
+
+
+    /**
+     * Create a BindRequest ready to be sent.
+     */
+    private BindRequestCodec createBindMessage( BindRequest bindRequest ) throws LdapException
+    {
+        // Create a new codec BindRequest object
+        BindRequestCodec bindRequestCodec = new BindRequestCodec();
+
+        // clear the mappings if any (in case of a second call to bind() without calling unBind())
+        clearMaps();
+        
+        // Set the new messageId
+        int newId = messageId.incrementAndGet();
+        bindRequest.setMessageId( newId );
+        bindRequestCodec.setMessageId( newId );
+
+        // Set the version
+        bindRequestCodec.setVersion( LdapConnectionConfig.LDAP_V3 );
+
+        // Set the name
+        try
+        {
+            LdapDN dn = new LdapDN( bindRequest.getName() );
+            bindRequestCodec.setName( dn );
         }
         catch ( InvalidNameException ine )
         {
@@ -1141,26 +1371,22 @@
         }
 
         // The authentication
-        request.setAuthentication( authentication );
-
-        // Stores the BindRequest into the message
-        bindMessage.setProtocolOP( request );
+        bindRequestCodec.setAuthentication( authentication );
 
         // Add the controls
-        setControls( bindRequest.getControls(), bindMessage );
+        setControls( bindRequest.getControls(), bindRequestCodec );
 
-        return bindMessage;
+        return bindRequestCodec;
     }
 
 
     /**
-     * Do a non-blocking bind
+     * Do an asynchronous bind, based on a BindRequest.
      *
      * @param bindRequest The BindRequest to send
-     * @param listener The listener 
      * @return BindFuture A future
      */
-    public BindFuture bind( BindRequest bindRequest, BindListener bindListener ) throws LdapException, IOException
+    public BindFuture bindAsync( BindRequest bindRequest ) throws LdapException, IOException
     {
         // First switch to anonymous state
         authenticated = false;
@@ -1176,36 +1402,27 @@
 
         int newId = bindMessage.getMessageId();
 
-        if ( bindListener != null )
-        {
-            // This is an asynchronous bind
-            listenerMap.put( newId, bindListener );
-        }
-
         LOG.debug( "-----------------------------------------------------------------" );
         LOG.debug( "Sending request \n{}", bindMessage );
 
-        BlockingQueue<BindResponse> bindResponseQueue = new LinkedBlockingQueue<BindResponse>();
-        respQueueMap.put( newId, bindResponseQueue );
-
-        // Create a future for this Bind opeation
-        BindFuture bindFuture = new BindFuture( bindResponseQueue );
+        // Create a future for this Bind operation
+        BindFuture bindFuture = new BindFuture( this, newId );
 
-        futureMap.put( newId, bindFuture );
-
-        if ( bindListener != null )
-        {
-            // If this is an asynchronous operation, associate the ID
-            // with the operation listener
-            listenerMap.put( newId, bindListener );
-        }
+        addToFutureMap( newId, bindFuture );
 
         // Send the request to the server
         WriteFuture writeFuture = ldapSession.write( bindMessage );
 
         // Wait for the message to be sent to the server
-        writeFuture.awaitUninterruptibly( timeOut );
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occured" );
+
+            throw new LdapException( TIME_OUT_ERROR );
+        }
         
+        // Ok, done return the future
         return bindFuture;
     }
 
@@ -1240,12 +1457,12 @@
         searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
 
         // Process the request in blocking mode
-        return searchInternal( searchRequest, null );
+        return search( searchRequest );
     }
 
 
     /**
-     * Do a search, on the base object, using the given filter. The
+     * Do an asynchronous search, on the base object, using the given filter. The
      * SearchRequest parameters default to :
      * Scope : ONE
      * DerefAlias : ALWAYS
@@ -1255,194 +1472,143 @@
      * Attributes : all the user's attributes.
      * This method is blocking.
      * 
-     * @param listener a SearchListener used to be informed when a result 
-     * has been found, or when the search is done
-     * @param baseObject The base for the search. It must be a valid
+     * @param baseDn The base for the search. It must be a valid
      * DN, and can't be emtpy
-     * @param filter The filter to use for this search. It can't be empty
+     * @param filterString The filter to use for this search. It can't be empty
+     * @param scope The sarch scope : OBJECT, ONELEVEL or SUBTREE 
      * @return A cursor on the result. 
      */
-    public void search( SearchRequest searchRequest, SearchListener listener ) throws LdapException
+    public SearchFuture searchAsync( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
     {
-        searchInternal( searchRequest, listener );
-    }
+        // Create a new SearchRequest object
+        SearchRequest searchRequest = new SearchRequest();
 
+        searchRequest.setBaseDn( baseDn );
+        searchRequest.setFilter( filter );
+        searchRequest.setScope( scope );
+        searchRequest.addAttributes( attributes );
+        searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
 
-    /**
-     * performs search in a synchronous mode (as if a null search listener is passed) 
-     * @see #search(SearchRequest, SearchListener)
-     */
-    public Cursor<SearchResponse> search( SearchRequest searchRequest ) throws LdapException
-    {
-        return searchInternal( searchRequest, null );
+        // Process the request in blocking mode
+        return searchAsync( searchRequest );
     }
 
 
-    private Cursor<SearchResponse> searchInternal( SearchRequest searchRequest, SearchListener searchListener )
-        throws LdapException
+    /**
+     * Do a search, on the base object, using the given filter. The
+     * SearchRequest parameters default to :
+     * Scope : ONE
+     * DerefAlias : ALWAYS
+     * SizeLimit : none
+     * TimeLimit : none
+     * TypesOnly : false
+     * Attributes : all the user's attributes.
+     * This method is blocking.
+     * 
+     * @param searchRequest The search request to send to the server
+     * @return A Future 
+     */
+    public SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException
     {
         // If the session has not been establish, or is closed, we get out immediately
         checkSession();
 
-        // Create the new message and update the messageId
-        LdapMessageCodec searchMessage = new LdapMessageCodec();
+        // Create the server request
+        SearchRequestCodec request = createSearchMessage( searchRequest );
 
-        // Creates the messageID and stores it into the 
-        // initial message and the transmitted message.
-        int newId = messageId.incrementAndGet();
-        searchRequest.setMessageId( newId );
-        searchMessage.setMessageId( newId );
+        LOG.debug( "-----------------------------------------------------------------" );
+        LOG.debug( "Sending request \n{}", request );
 
-        // Create a new codec SearchRequest object
-        SearchRequestCodec request = new SearchRequestCodec();
+        SearchFuture searchFuture = new SearchFuture( this, request.getMessageId() );
+        addToFutureMap( request.getMessageId(), searchFuture );
 
-        // Set the name
-        try
-        {
-            LdapDN dn = new LdapDN( searchRequest.getBaseDn() );
-            request.setBaseObject( dn );
-        }
-        catch ( InvalidNameException ine )
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( request );
+
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
         {
-            String msg = "The given dn '" + searchRequest.getBaseDn() + "' is not valid";
-            LOG.error( msg );
-            LdapException ldapException = new LdapException( msg );
-            ldapException.initCause( ine );
+            // We didn't received anything : this is an error
+            LOG.error( "Search failed : timeout occured" );
 
-            throw ldapException;
+            throw new LdapException( TIME_OUT_ERROR );
         }
+        
+        // Ok, done return the future
+        return searchFuture;
 
-        // Set the scope
-        request.setScope( searchRequest.getScope() );
-
-        // Set the typesOnly flag
-        request.setDerefAliases( searchRequest.getDerefAliases().getValue() );
-
-        // Set the timeLimit
-        request.setTimeLimit( searchRequest.getTimeLimit() );
-
-        // Set the sizeLimit
-        request.setSizeLimit( searchRequest.getSizeLimit() );
-
-        // Set the typesOnly flag
-        request.setTypesOnly( searchRequest.getTypesOnly() );
+    }
 
-        // Set the filter
-        Filter filter = null;
 
+    /**
+     * Performs search in a synchronous mode.
+     *  
+     * @param searchRequest The search configuration
+     * @return A {@link Cursor} containing Entries and Referencs
+     * @throws LdapException @TODO
+     */
+    public Cursor<SearchResponse> search( SearchRequest searchRequest ) throws LdapException
+    {
+        SearchFuture searchFuture = searchAsync( searchRequest );
+        int messageId = searchRequest.getMessageId();
+        
+        // Read the response, waiting for it if not available immediately
         try
         {
-            ExprNode filterNode = FilterParser.parse( searchRequest.getFilter() );
+            long timeout = getTimeout( searchRequest.getTimeout() );
+            SearchResponse searchResponse = null;
+            List<SearchResponse> searchResponses = new ArrayList<SearchResponse>();
+
+            // We may have more than one response, so loop on the queue
+            do
+            {
+                searchResponse = ( SearchResponse ) searchFuture.get( timeout, TimeUnit.MILLISECONDS );
+
+                // Check that we didn't get out because of a timeout
+                if ( searchResponse == null )
+                {
+                    // Send an abandon request
+                    abandon( messageId );
+
+                    // We didn't received anything : this is an error
+                    LOG.error( "Search failed : timeout occured" );
+                    
+                    // Remove the future from the map
+                    removeFromFutureMaps( messageId );
 
-            filter = LdapTransformer.transformFilter( filterNode );
-        }
-        catch ( ParseException pe )
-        {
-            String msg = "The given filter '" + searchRequest.getFilter() + "' is not valid";
-            LOG.error( msg );
-            LdapException ldapException = new LdapException( msg );
-            ldapException.initCause( pe );
-
-            throw ldapException;
-        }
-
-        request.setFilter( filter );
+                    throw new LdapException( TIME_OUT_ERROR );
+                }
+                
+                if ( !( searchResponse instanceof SearchResultDone ) )
+                {
+                    searchResponses.add( searchResponse );
+                }
+            }
+            while ( !( searchResponse instanceof SearchResultDone ) );
 
-        // Set the attributes
-        Set<String> attributes = searchRequest.getAttributes();
+            LOG.debug( "Search successful, {} elements found", searchResponses.size() );
 
-        if ( attributes != null )
+            return new ListCursor<SearchResponse>( searchResponses );
+        }
+        catch ( InterruptedException ie )
         {
-            for ( String attribute : attributes )
-            {
-                request.addAttribute( attribute );
-            }
+            LOG.error( OPERATION_CANCELLED, ie );
+            throw new LdapException( OPERATION_CANCELLED, ie );
         }
-
-        // Stores the SearchRequest into the message
-        searchMessage.setProtocolOP( request );
-
-        // Add the controls
-        setControls( searchRequest.getControls(), searchMessage );
-
-        LOG.debug( "-----------------------------------------------------------------" );
-        LOG.debug( "Sending request \n{}", searchMessage );
-
-        BlockingQueue<Response> searchResponseQueue = new LinkedBlockingQueue<Response>();
-        respQueueMap.put( newId, searchResponseQueue );
-
-        ResponseFuture searchFuture = new ResponseFuture( searchResponseQueue );
-        futureMap.put( newId, searchFuture );
-
-        // Send the request to the server
-        ldapSession.write( searchMessage );
-
-        if ( searchListener == null )
+        catch ( Exception e )
         {
-            // Read the response, waiting for it if not available immediately
-            try
-            {
-                long timeout = getTimeout( searchRequest.getTimeout() );
-                SearchResponse response = null;
-                List<SearchResponse> searchResponses = new ArrayList<SearchResponse>();
-
-                // We may have more than one response, so loop on the queue
-                do
-                {
-                    response = ( SearchResponse ) searchFuture.get( timeout, TimeUnit.MILLISECONDS );
-
-                    // Check that we didn't get out because of a timeout
-                    if ( response == null )
-                    {
-                        // Send an abandon request
-                        abandon( searchMessage.getSearchRequest().getMessageId() );
-
-                        // We didn't received anything : this is an error
-                        LOG.error( "Search failed : timeout occured" );
-
-                        throw new LdapException( TIME_OUT_ERROR );
-                    }
-                    else
-                    {
-                        if ( ( response instanceof SearchResultEntry ) ||
-                             ( response instanceof SearchResultReference ) )
-                        {
-                            searchResponses.add( response );
-                        }
-                    }
-                }
-                while ( !( response instanceof SearchResultDone ) );
-
-                LOG.debug( "Search successful, {} elements found", searchResponses.size() );
+            LOG.error( NO_RESPONSE_ERROR, e );
+            LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
+            ldapException.initCause( e );
 
-                return new ListCursor<SearchResponse>( searchResponses );
-            }
-            catch ( InterruptedException ie )
+            // Send an abandon request
+            if ( !searchFuture.isCancelled() )
             {
-                LOG.error( OPERATION_CANCELLED, ie );
-                throw new LdapException( OPERATION_CANCELLED, ie );
+                abandon( messageId );
             }
-            catch ( Exception e )
-            {
-                LOG.error( NO_RESPONSE_ERROR, e );
-                LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
-                ldapException.initCause( e );
-
-                // Send an abandon request
-                if ( !searchFuture.isCancelled() )
-                {
-                    abandon( searchMessage.getSearchRequest().getMessageId() );
-                }
 
-                throw ldapException;
-            }
-        }
-        else
-        {
-            // The listener will be called on a MessageReceived event,
-            // no need to create a cursor
-            listenerMap.put( newId, searchListener );
-            return null;
+            throw ldapException;
         }
     }
 
@@ -1461,22 +1627,16 @@
         // Create the UnbindRequest
         UnBindRequestCodec unbindRequest = new UnBindRequestCodec();
 
-        // Encode the request
-        LdapMessageCodec unbindMessage = new LdapMessageCodec();
-
         // Creates the messageID and stores it into the 
         // initial message and the transmitted message.
         int newId = messageId.incrementAndGet();
         unbindRequest.setMessageId( newId );
-        unbindMessage.setMessageId( newId );
-
-        unbindMessage.setProtocolOP( unbindRequest );
 
         LOG.debug( "-----------------------------------------------------------------" );
-        LOG.debug( "Sending Unbind request \n{}", unbindMessage );
+        LOG.debug( "Sending Unbind request \n{}", unbindRequest );
 
         // Send the request to the server
-        WriteFuture unbindFuture = ldapSession.write( unbindMessage );
+        WriteFuture unbindFuture = ldapSession.write( unbindRequest );
 
         unbindFuture.awaitUninterruptibly();
         
@@ -1528,59 +1688,79 @@
     {
         // Feed the response and store it into the session
         LdapMessageCodec response = ( LdapMessageCodec ) message;
-
-        LOG.debug( "-------> {} Message received <-------", response.getMessageTypeName() );
+        
+        LOG.debug( "-------> {} Message received <-------", response );
 
         // this check is necessary to prevent adding an abandoned operation's
         // result(s) to corresponding queue
-        ResponseFuture rf = futureMap.get( response.getMessageId() );
+        ResponseFuture<? extends Response> responseFuture = peekFromFutureMap( response.getMessageId() );
 
-        if ( rf == null )
+        if ( responseFuture == null )
         {
-            LOG.error( "There is no future associated with the messageId {}, ignoring the message", response
+            LOG.info( "There is no future associated with the messageId {}, ignoring the message", response
                 .getMessageId() );
             return;
         }
 
-        SearchListener searchListener = null;
         int messageId = response.getMessageId();
 
         switch ( response.getMessageType() )
         {
-            case LdapConstants.ADD_RESPONSE:
-                // Store the response into the responseQueue
-                AddResponseCodec addRespCodec = response.getAddResponse();
+            case ADD_RESPONSE:
+                // Transform the response
+                AddResponseCodec addRespCodec = (AddResponseCodec)response;
                 addRespCodec.addControl( response.getCurrentControl() );
                 addRespCodec.setMessageId( messageId );
 
-                futureMap.remove( addRespCodec.getMessageId() );
-                AddListener addListener = ( AddListener ) listenerMap.remove( addRespCodec.getMessageId() );
-                AddResponse addResp = convert( addRespCodec );
+                AddResponse addResponse = convert( addRespCodec );
                 
-                if ( addListener != null )
+                AddFuture addFuture = (AddFuture)responseFuture;
+
+                if ( addFuture == null )
                 {
-                    addListener.entryAdded( this, addResp );
+                    LOG.error( "AddFuture is null" );
+                    throw new LdapException( "AddFuture is null"  );
                 }
-                else
+                
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
                 {
-                    BlockingQueue<AddResponse> respQueue = (BlockingQueue<AddResponse>)respQueueMap.remove( messageId );
-                    respQueue.add( addResp );
+                    if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Add successful : {}", addResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Add failed : {}", addResponse );
+                    }
                 }
+
+                // Store the response into the future
+                addFuture.set( addResponse );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
                 
                 break;
 
-            case LdapConstants.BIND_RESPONSE:
-                // Store the response into the responseQueue
-                BindResponseCodec bindResponseCodec = response.getBindResponse();
+            case BIND_RESPONSE:
+                // Transform the response
+                BindResponseCodec bindResponseCodec = (BindResponseCodec)response;
                 bindResponseCodec.setMessageId( messageId );
                 bindResponseCodec.addControl( response.getCurrentControl() );
                 BindResponse bindResponse = convert( bindResponseCodec );
 
-                futureMap.remove( bindResponseCodec.getMessageId() );
+                BindFuture bindFuture = (BindFuture)responseFuture;
 
+                if ( bindFuture == null )
+                {
+                    LOG.error( "BindFuture is null" );
+                    throw new LdapException( "BindFuture is null"  );
+                }
+                
                 // remove the listener from the listener map
-                BindListener bindListener = ( BindListener ) listenerMap.remove( bindResponseCodec.getMessageId() );
-
                 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
                 {
                     authenticated = true;
@@ -1594,216 +1774,308 @@
                     LOG.debug( "Bind failed : {}", bindResponse );
                 }
 
-                if ( bindListener != null )
-                {
-                    bindListener.bindCompleted( this, bindResponse );
-                }
+                // Store the response into the future
+                bindFuture.set( bindResponse );
 
-                // Store the response into the responseQueue
-                BlockingQueue<BindResponse> bindResponseQueue = (BlockingQueue<BindResponse>)respQueueMap.remove( messageId );
-                bindResponseQueue.add( bindResponse );
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
 
                 break;
 
-            case LdapConstants.COMPARE_RESPONSE:
-                // Store the response into the responseQueue
-                CompareResponseCodec compResCodec = response.getCompareResponse();
+            case COMPARE_RESPONSE:
+                // Transform the response
+                CompareResponseCodec compResCodec = (CompareResponseCodec)response;
                 compResCodec.setMessageId( messageId );
                 compResCodec.addControl( response.getCurrentControl() );
-                CompareResponse compareResponse = convert( compResCodec );
-
-                futureMap.remove( compareResponse.getMessageId() );
 
-                CompareListener listener = ( CompareListener ) listenerMap.remove( compareResponse.getMessageId() );
+                CompareResponse compareResponse = convert( compResCodec );
                 
-                if ( listener != null )
+                CompareFuture compareFuture = (CompareFuture)responseFuture;
+
+                if ( compareFuture == null )
                 {
-                    listener.attributeCompared( this, compareResponse );
+                    LOG.error( "CompareFuture is null" );
+                    throw new LdapException( "CompareFuture is null"  );
                 }
-                else
+                
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
                 {
-                    BlockingQueue<CompareResponse> compareResponseQueue = (BlockingQueue<CompareResponse>)respQueueMap.remove( messageId );
-                    compareResponseQueue.add( compareResponse );
+                    if ( compareResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Compare successful : {}", compareResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Compare failed : {}", compareResponse );
+                    }
                 }
 
+                // Store the response into the future
+                compareFuture.set( compareResponse );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+                
                 break;
 
-            case LdapConstants.DEL_RESPONSE:
-                // Store the response into the responseQueue
-                DelResponseCodec delRespCodec = response.getDelResponse();
-                delRespCodec.setMessageId( messageId );
+            case DEL_RESPONSE:
+                // Transform the response
+                DelResponseCodec delRespCodec = (DelResponseCodec)response;
                 delRespCodec.addControl( response.getCurrentControl() );
-                DeleteResponse delResponse = convert( delRespCodec );
+                delRespCodec.setMessageId( messageId );
 
-                futureMap.remove( delResponse.getMessageId() );
-                DeleteListener delListener = ( DeleteListener ) listenerMap.remove( delResponse.getMessageId() );
+                DeleteResponse deleteResponse = convert( delRespCodec );
                 
-                if ( delListener != null )
+                DeleteFuture deleteFuture = (DeleteFuture)responseFuture;
+
+                if ( deleteFuture == null )
                 {
-                    delListener.entryDeleted( this, delResponse );
+                    LOG.error( "DeleteFuture is null" );
+                    throw new LdapException( "DeleteFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    BlockingQueue<DeleteResponse> delResponseQueue = (BlockingQueue<DeleteResponse>)respQueueMap.remove( messageId );
-                    delResponseQueue.add( delResponse );
+                    if ( deleteResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Delete successful : {}", deleteResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Delete failed : {}", deleteResponse );
+                    }
                 }
+
+                // Store the response into the future
+                deleteFuture.set( deleteResponse );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
                 
                 break;
 
-            case LdapConstants.EXTENDED_RESPONSE:
-                ExtendedResponseCodec extResCodec = response.getExtendedResponse();
+            case EXTENDED_RESPONSE:
+                // Transform the response
+                ExtendedResponseCodec extResCodec = (ExtendedResponseCodec)response;
                 extResCodec.setMessageId( messageId );
                 extResCodec.addControl( response.getCurrentControl() );
 
-                ExtendedResponse extResponse = convert( extResCodec );
-                ExtendedListener extListener = ( ExtendedListener ) listenerMap.remove( extResCodec.getMessageId() );
+                ExtendedResponse extendedResponse = convert( extResCodec );
+
+                ExtendedFuture extendedFuture = (ExtendedFuture)responseFuture;
 
-                if ( extListener != null )
+                if ( extendedFuture == null )
                 {
-                    extListener.extendedOperationCompleted( this, extResponse );
+                    LOG.error( "ExtendedFuture is null" );
+                    throw new LdapException( "extendedFuture is null"  );
                 }
-                else
+
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
                 {
-                    // Store the response into the responseQueue
-                    BlockingQueue<ExtendedResponse> extendedResponseQueue = (BlockingQueue<ExtendedResponse>)respQueueMap.remove( messageId );
-                    extendedResponseQueue.add( extResponse );
+                    if ( extendedResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Extended successful : {}", extendedResponse );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Extended failed : {}", extendedResponse );
+                    }
                 }
 
+                // Store the response into the future
+                extendedFuture.set( extendedResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
                 break;
 
             //FIXME the way we handle the intermediate responses is broken
-            case LdapConstants.INTERMEDIATE_RESPONSE:
+            case INTERMEDIATE_RESPONSE:
                 // Store the response into the responseQueue
-                IntermediateResponseCodec intermediateResponseCodec = response.getIntermediateResponse();
+                IntermediateResponseCodec intermediateResponseCodec = (IntermediateResponseCodec)response;
                 intermediateResponseCodec.setMessageId( messageId );
                 intermediateResponseCodec.addControl( response.getCurrentControl() );
 
                 IntermediateResponse intrmResp = convert( intermediateResponseCodec );
-                IntermediateResponseListener intrmListener = ( IntermediateResponseListener ) listenerMap
-                    .get( intermediateResponseCodec.getMessageId() );
                 
-                if ( intrmListener != null )
-                {
-                    intrmListener.responseReceived( this, intrmResp );
-                }
-                else
-                {
-                    // Store the response into the responseQueue
-                    BlockingQueue<IntermediateResponse> intermediateResponseQueue = (BlockingQueue<IntermediateResponse>)respQueueMap.remove( messageId );
-                    intermediateResponseQueue.add( intrmResp );
-                }
+                // Store the response into the responseQueue
+                BlockingQueue<IntermediateResponse> intermediateResponseQueue = (BlockingQueue<IntermediateResponse>)respQueueMap.remove( messageId );
+                intermediateResponseQueue.add( intrmResp );
 
                 break;
 
-            case LdapConstants.MODIFY_RESPONSE:
-                ModifyResponseCodec modRespCodec = response.getModifyResponse();
+            case MODIFY_RESPONSE:
+                // Transform the response
+                ModifyResponseCodec modRespCodec = (ModifyResponseCodec)response;
                 modRespCodec.setMessageId( messageId );
                 modRespCodec.addControl( response.getCurrentControl() );
-                ModifyResponse modResp = convert( modRespCodec );
 
-                futureMap.remove( modResp.getMessageId() );
-                ModifyListener modListener = ( ModifyListener ) listenerMap.remove( modResp.getMessageId() );
+                ModifyResponse modifyResp = convert( modRespCodec );
+                
+                ModifyFuture modifyFuture = (ModifyFuture)responseFuture;
 
-                if ( modListener != null )
+                if ( modifyFuture == null )
                 {
-                    modListener.modifyCompleted( this, modResp );
+                    LOG.error( "ModifyFuture is null" );
+                    throw new LdapException( "ModifyFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    BlockingQueue<ModifyResponse> modifyResponseQueue = (BlockingQueue<ModifyResponse>)respQueueMap.remove( messageId );
-                    modifyResponseQueue.add( modResp );
+                    if ( modifyResp.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "ModifyFuture successful : {}", modifyResp );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "ModifyFuture failed : {}", modifyResp );
+                    }
                 }
 
+                // Store the response into the future
+                modifyFuture.set( modifyResp );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+                
                 break;
 
-            case LdapConstants.MODIFYDN_RESPONSE:
+            case MODIFYDN_RESPONSE:
+                // Transform the response
+                ModifyDNResponseCodec modDnRespCodec = (ModifyDNResponseCodec)response;
+                modDnRespCodec.setMessageId( messageId );
+                modDnRespCodec.addControl( response.getCurrentControl() );
 
-                ModifyDNResponseCodec modDnCodec = response.getModifyDNResponse();
-                modDnCodec.addControl( response.getCurrentControl() );
-                modDnCodec.setMessageId( messageId );
-                ModifyDnResponse modDnResp = convert( modDnCodec );
-
-                futureMap.remove( modDnCodec.getMessageId() );
-                ModifyDnListener modDnListener = ( ModifyDnListener ) listenerMap.remove( modDnCodec.getMessageId() );
+                ModifyDnResponse modifyDnResp = convert( modDnRespCodec );
+                
+                ModifyDnFuture modifyDnFuture = (ModifyDnFuture)responseFuture;
 
-                if ( modDnListener != null )
+                if ( modifyDnFuture == null )
                 {
-                    modDnListener.modifyDnCompleted( this, modDnResp );
+                    LOG.error( "ModifyDNFuture is null" );
+                    throw new LdapException( "ModifyDNFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    // Store the response into the responseQueue
-                    BlockingQueue<ModifyDnResponse> modDnResponseQueue = (BlockingQueue<ModifyDnResponse>)respQueueMap.remove( messageId );
-                    modDnResponseQueue.add( modDnResp );
+                    if ( modifyDnResp.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "ModifyDN successful : {}", modifyDnResp );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "ModifyDN failed : {}", modifyDnResp );
+                    }
                 }
 
+                // Store the response into the future
+                modifyDnFuture.set( modifyDnResp );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+                
                 break;
-
-            case LdapConstants.SEARCH_RESULT_DONE:
+                
+            case SEARCH_RESULT_DONE:
                 // Store the response into the responseQueue
-                SearchResultDoneCodec searchResultDoneCodec = response.getSearchResultDone();
+                SearchResultDoneCodec searchResultDoneCodec = (SearchResultDoneCodec)response;
                 searchResultDoneCodec.setMessageId( messageId );
                 searchResultDoneCodec.addControl( response.getCurrentControl() );
-                SearchResultDone srchDone = convert( searchResultDoneCodec );
+                SearchResultDone searchResultDone = convert( searchResultDoneCodec );
 
-                futureMap.remove( searchResultDoneCodec.getMessageId() );
-                // search listener has to be removed from listener map only here
-                searchListener = ( SearchListener ) listenerMap.remove( searchResultDoneCodec.getMessageId() );
+                SearchFuture searchFuture = (SearchFuture)responseFuture;
                 
-                if ( searchListener != null )
+                if ( searchFuture == null )
                 {
-                    searchListener.searchDone( this, srchDone );
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    BlockingQueue<SearchResultDone> searchDoneResponseQueue = (BlockingQueue<SearchResultDone>)respQueueMap.remove( messageId );
-                    searchDoneResponseQueue.add( srchDone );
+                    if ( searchResultDone.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                    {
+                        // Everything is fine, return the response
+                        LOG.debug( "Search successful : {}", searchResultDone );
+                    }
+                    else
+                    {
+                        // We have had an error
+                        LOG.debug( "Search failed : {}", searchResultDone );
+                    }
                 }
 
+                // Store the response into the future
+                searchFuture.set( searchResultDone );
+                
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
                 break;
 
-            case LdapConstants.SEARCH_RESULT_ENTRY:
+            case SEARCH_RESULT_ENTRY:
                 // Store the response into the responseQueue
-                SearchResultEntryCodec searchResultEntryCodec = response.getSearchResultEntry();
+                SearchResultEntryCodec searchResultEntryCodec = (SearchResultEntryCodec)response;
                 searchResultEntryCodec.setMessageId( messageId );
                 searchResultEntryCodec.addControl( response.getCurrentControl() );
 
                 SearchResultEntry srchEntry = convert( searchResultEntryCodec );
-                searchListener = ( SearchListener ) listenerMap.get( searchResultEntryCodec.getMessageId() );
 
-                if ( searchListener != null )
+                searchFuture = (SearchFuture)responseFuture;
+                
+                if ( searchFuture == null )
                 {
-                    searchListener.entryFound( this, srchEntry );
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    // shouldn't call addToRespQueueAndRemoveQueueRef
-                    BlockingQueue<SearchResponse> searchResponsequeue = (BlockingQueue<SearchResponse>)respQueueMap.get( messageId );
-                    searchResponsequeue.add( srchEntry );
+                    LOG.debug( "Search entry found : {}", srchEntry );
                 }
 
+                // Store the response into the future
+                searchFuture.set( srchEntry );
+                
                 break;
 
-            case LdapConstants.SEARCH_RESULT_REFERENCE:
+            case SEARCH_RESULT_REFERENCE:
                 // Store the response into the responseQueue
-                SearchResultReferenceCodec searchResultReferenceCodec = response.getSearchResultReference();
+                SearchResultReferenceCodec searchResultReferenceCodec = (SearchResultReferenceCodec)response;
                 searchResultReferenceCodec.setMessageId( messageId );
                 searchResultReferenceCodec.addControl( response.getCurrentControl() );
 
-                SearchResultReference srchRef = convert( searchResultReferenceCodec );
-                searchListener = ( SearchListener ) listenerMap.get( searchResultReferenceCodec.getMessageId() );
+                SearchResultReference searchResultReference = convert( searchResultReferenceCodec );
+
+                searchFuture = (SearchFuture)responseFuture;
                 
-                if ( searchListener != null )
+                if ( searchFuture == null )
                 {
-                    searchListener.referralFound( this, srchRef );
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
                 }
-                else
+                
+                if ( LOG.isDebugEnabled() )
                 {
-                    // shouldn't call addToRespQueueAndRemoveQueueRef
-                    BlockingQueue<SearchResponse> searchResponsequeue = (BlockingQueue<SearchResponse>)respQueueMap.get( messageId );
-                    searchResponsequeue.add( srchRef );
+                    LOG.debug( "Search reference found : {}", searchResultReference );
                 }
 
+                // Store the response into the future
+                searchFuture.set( searchResultReference );
+                
                 break;
 
             default:
@@ -1838,78 +2110,123 @@
             modReq.addModification( itr.next(), modOp );
         }
 
-        return modify( modReq, null );
+        return modify( modReq );
     }
 
 
     /**
-     * 
-     * performs modify operation based on the modifications present in the ModifyRequest.
+     * Performs an modify operation based on the modifications present in 
+     * the ModifyRequest.
      *
      * @param modRequest the request for modify operation
-     * @param listener callback listener which will be called after the operation is completed
-     * @return the modify operation's response, null if non-null listener is provided
+     * @return the modify operation's r"esponse
      * @throws LdapException in case of modify operation failure or timeout happens
      */
-    public ModifyResponse modify( ModifyRequest modRequest, ModifyListener listener ) throws LdapException
+    public ModifyResponse modify( ModifyRequest modRequest ) throws LdapException
+    {
+        ModifyFuture modifyFuture = modifyAsync( modRequest );
+        
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            long timeout = getTimeout( modRequest.getTimeout() );
+
+            // Get the response, blocking
+            ModifyResponse modifyResponse = ( ModifyResponse ) modifyFuture.get( timeout, TimeUnit.MILLISECONDS );
+            
+            if ( modifyResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Modify failed : timeout occured" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+            
+            if ( modifyResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Modify successful : {}", modifyResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Modify failed : {}", modifyResponse );
+            }
+
+            return modifyResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !modifyFuture.isCancelled() )
+            {
+                abandon( modRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        catch ( Exception ie )
+        {
+            ie.printStackTrace();
+            
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+            LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
+            ldapException.initCause( ie );
+
+            // Send an abandon request
+            if ( !modifyFuture.isCancelled() )
+            {
+                abandon( modRequest.getMessageId() );
+            }
+
+            throw ldapException;
+        }
+    }
+
+
+    /**
+     * Performs an asynchronous modify operation based on the modifications present in 
+     * the ModifyRequest.
+     *
+     * @param modRequest the request for modify operation
+     * @return the modify operation's future
+     * @throws LdapException in case of modify operation failure or timeout happens
+     */
+    public ModifyFuture modifyAsync( ModifyRequest modRequest ) throws LdapException
     {
         checkSession();
 
-        LdapMessageCodec modifyMessage = new LdapMessageCodec();
+        ModifyRequestCodec modReqCodec = new ModifyRequestCodec();
 
         int newId = messageId.incrementAndGet();
         modRequest.setMessageId( newId );
-        modifyMessage.setMessageId( newId );
+        modReqCodec.setMessageId( newId );
 
-        ModifyRequestCodec modReqCodec = new ModifyRequestCodec();
         modReqCodec.setModifications( modRequest.getMods() );
         modReqCodec.setObject( modRequest.getDn() );
 
-        modifyMessage.setProtocolOP( modReqCodec );
-        setControls( modRequest.getControls(), modifyMessage );
-
-        BlockingQueue<Response> modifyResponseQueue = new LinkedBlockingQueue<Response>();
-        respQueueMap.put( newId, modifyResponseQueue );
-
-        ResponseFuture modifyFuture = new ResponseFuture( modifyResponseQueue );
-        futureMap.put( newId, modifyFuture );
+        setControls( modRequest.getControls(), modReqCodec );
+        
+        ModifyFuture modifyFuture = new ModifyFuture( this, newId );
+        addToFutureMap( newId, modifyFuture );
 
-        ldapSession.write( modifyMessage );
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( modReqCodec );
 
-        ModifyResponse response = null;
-        if ( listener == null )
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
         {
-            try
-            {
-                long timeout = getTimeout( modRequest.getTimeout() );
-                response = ( ModifyResponse ) modifyFuture.get( timeout, TimeUnit.MILLISECONDS );
-
-                if ( response == null )
-                {
-                    LOG.error( "Modify failed : timeout occured" );
-
-                    throw new LdapException( TIME_OUT_ERROR );
-                }
-            }
-            catch ( InterruptedException ie )
-            {
-                LOG.error( OPERATION_CANCELLED, ie );
-                throw new LdapException( OPERATION_CANCELLED, ie );
-            }
-            catch ( Exception e )
-            {
-                LOG.error( NO_RESPONSE_ERROR );
-                removeFromMaps( newId );
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
 
-                throw new LdapException( NO_RESPONSE_ERROR, e );
-            }
-        }
-        else
-        {
-            listenerMap.put( newId, listener );
+            throw new LdapException( TIME_OUT_ERROR );
         }
-
-        return response;
+        
+        // Ok, done return the future
+        return modifyFuture;
     }
 
 
@@ -1982,7 +2299,7 @@
         modDnRequest.setNewRdn( newRdn );
         modDnRequest.setDeleteOldRdn( deleteOldRdn );
 
-        return modifyDn( modDnRequest, null );
+        return modifyDn( modDnRequest );
     }
 
 
@@ -2017,10 +2334,83 @@
         modDnRequest.setEntryDn( entryDn );
         modDnRequest.setNewSuperior( newSuperiorDn );
 
-        //TODO not setting the below value is resulting in error
-        modDnRequest.setNewRdn( entryDn.getRdn() );
+        //TODO not setting the below value is resulting in error
+        modDnRequest.setNewRdn( entryDn.getRdn() );
+
+        return modifyDn( modDnRequest );
+    }
+
+
+    /**
+     * 
+     * performs the modifyDn operation based on the given ModifyDnRequest.
+     *
+     * @param modDnRequest the request
+     * @return modifyDn operations response, null if non-null listener is provided
+     * @throws LdapException
+     */
+    public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException
+    {
+        ModifyDnFuture modifyDnFuture = modifyDnAsync( modDnRequest );
+        
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            long timeout = getTimeout( modDnRequest.getTimeout() );
+
+            // Get the response, blocking
+            ModifyDnResponse modifyDnResponse = ( ModifyDnResponse ) modifyDnFuture.get( timeout, TimeUnit.MILLISECONDS );
+            
+            if ( modifyDnResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "ModifyDN failed : timeout occured" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+            
+            if ( modifyDnResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "ModifyDN successful : {}", modifyDnResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Modify failed : {}", modifyDnResponse );
+            }
+
+            return modifyDnResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !modifyDnFuture.isCancelled() )
+            {
+                abandon( modDnRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        catch ( Exception ie )
+        {
+            ie.printStackTrace();
+            
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+            LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
+            ldapException.initCause( ie );
+
+            // Send an abandon request
+            if ( !modifyDnFuture.isCancelled() )
+            {
+                abandon( modDnRequest.getMessageId() );
+            }
 
-        return modifyDn( modDnRequest, null );
+            throw ldapException;
+        }
     }
 
 
@@ -2033,70 +2423,40 @@
      * @return modifyDn operations response, null if non-null listener is provided
      * @throws LdapException
      */
-    public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest, ModifyDnListener listener ) throws LdapException
+    public ModifyDnFuture modifyDnAsync( ModifyDnRequest modDnRequest ) throws LdapException
     {
         checkSession();
 
-        LdapMessageCodec modifyDnMessage = new LdapMessageCodec();
+        ModifyDNRequestCodec modDnCodec = new ModifyDNRequestCodec();
 
         int newId = messageId.incrementAndGet();
         modDnRequest.setMessageId( newId );
-        modifyDnMessage.setMessageId( newId );
+        modDnCodec.setMessageId( newId );
 
-        ModifyDNRequestCodec modDnCodec = new ModifyDNRequestCodec();
         modDnCodec.setEntry( modDnRequest.getEntryDn() );
         modDnCodec.setNewRDN( modDnRequest.getNewRdn() );
         modDnCodec.setDeleteOldRDN( modDnRequest.isDeleteOldRdn() );
         modDnCodec.setNewSuperior( modDnRequest.getNewSuperior() );
 
-        modifyDnMessage.setProtocolOP( modDnCodec );
-        setControls( modDnRequest.getControls(), modifyDnMessage );
+        setControls( modDnRequest.getControls(), modDnCodec );
 
-        BlockingQueue<Response> modifyDNResponseQueue = new LinkedBlockingQueue<Response>();
-        respQueueMap.put( newId, modifyDNResponseQueue );
+        ModifyDnFuture modifyDnFuture = new ModifyDnFuture( this, newId );
+        addToFutureMap( newId, modifyDnFuture );
 
-        ResponseFuture modifyDNFuture = new ResponseFuture( modifyDNResponseQueue );
-        futureMap.put( newId, modifyDNFuture );
-
-        ldapSession.write( modifyDnMessage );
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( modDnCodec );
 
-        if ( listener == null )
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
         {
-            ModifyDnResponse response = null;
-            try
-            {
-                long timeout = getTimeout( modDnRequest.getTimeout() );
-                response = ( ModifyDnResponse ) modifyDNFuture.get( timeout, TimeUnit.MILLISECONDS );
-
-                if ( response == null )
-                {
-                    LOG.error( "Modifying DN failed : timeout occured" );
-
-                    throw new LdapException( TIME_OUT_ERROR );
-                }
-            }
-            catch ( InterruptedException ie )
-            {
-                LOG.error( OPERATION_CANCELLED, ie );
-                throw new LdapException( OPERATION_CANCELLED, ie );
-            }
-            catch ( Exception e )
-            {
-                LOG.error( NO_RESPONSE_ERROR );
-                removeFromMaps( newId );
-
-                LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
-                ldapException.initCause( e );
-                throw ldapException;
-            }
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
 
-            return response;
-        }
-        else
-        {
-            listenerMap.put( newId, listener );
-            return null;
+            throw new LdapException( TIME_OUT_ERROR );
         }
+        
+        // Ok, done return the future
+        return modifyDnFuture;
     }
 
 
@@ -2126,7 +2486,7 @@
         {
             DeleteRequest deleteRequest = new DeleteRequest( new LdapDN( dn ) );
 
-            return delete( deleteRequest, null );
+            return delete( deleteRequest );
         }
         catch ( InvalidNameException e )
         {
@@ -2146,7 +2506,7 @@
     {
         DeleteRequest deleteRequest = new DeleteRequest( dn );
 
-        return delete( deleteRequest, null );
+        return delete( deleteRequest );
     }
 
 
@@ -2165,7 +2525,7 @@
         {
             DeleteRequest delRequest = new DeleteRequest( dn );
             delRequest.add( new ControlImpl( treeDeleteOid ) );
-            return delete( delRequest, null );
+            return delete( delRequest );
         }
         else
         {
@@ -2195,7 +2555,7 @@
             {
                 DeleteRequest delRequest = new DeleteRequest( ldapDn );
                 delRequest.add( new ControlImpl( treeDeleteOid ) );
-                return delete( delRequest, null );
+                return delete( delRequest );
             }
             else
             {
@@ -2272,7 +2632,7 @@
                 LOG.debug( "deleting {}", dn.getName() );
                 cursorMap.remove( dn );
                 cursor.close();
-                delResponse = delete( new DeleteRequest( dn ), listener );
+                delResponse = delete( new DeleteRequest( dn ) );
             }
             else
             {
@@ -2291,7 +2651,7 @@
                 cursorMap.remove( dn );
                 cursor.close();
                 LOG.debug( "deleting {}", dn.getName() );
-                delResponse = delete( new DeleteRequest( dn ), listener );
+                delResponse = delete( new DeleteRequest( dn ) );
             }
         }
         catch ( Exception e )
@@ -2306,88 +2666,115 @@
 
 
     /**
-     * Performs a synchronous delete operation based on the delete request object.
+     * Performs a delete operation based on the delete request object.
      *  
-     * @param delRequest the delete operation's request
+     * @param deleteRequest the delete operation's request
      * @return delete operation's response, null if a non-null listener value is provided
      * @throws LdapException If the DN is not valid or if the deletion failed
      */
-    public DeleteResponse delete( DeleteRequest delRequest ) throws LdapException
+    public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
     {
-        // Just call the delete method with a null listener
-        return delete( delRequest, null );
-    }
+        DeleteFuture deleteFuture = deleteAsync( deleteRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            long timeout = getTimeout( deleteRequest.getTimeout() );
+
+            // Get the response, blocking
+            DeleteResponse delResponse = ( DeleteResponse ) deleteFuture.get( timeout, TimeUnit.MILLISECONDS );
+            
+            if ( delResponse == null )
+            {
+                // We didn't received anything : this is an error
+                LOG.error( "Delete failed : timeout occured" );
+                throw new LdapException( TIME_OUT_ERROR );
+            }
+            
+            if ( delResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+            {
+                // Everything is fine, return the response
+                LOG.debug( "Delete successful : {}", delResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Delete failed : {}", delResponse );
+            }
+
+            return delResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !deleteFuture.isCancelled() )
+            {
+                abandon( deleteRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Del failed : timeout occured" );
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        catch ( Exception ie )
+        {
+            ie.printStackTrace();
+            
+            // Catch all other exceptions
+            LOG.error( NO_RESPONSE_ERROR, ie );
+            LdapException ldapException = new LdapException( NO_RESPONSE_ERROR );
+            ldapException.initCause( ie );
 
+            // Send an abandon request
+            if ( !deleteFuture.isCancelled() )
+            {
+                abandon( deleteRequest.getMessageId() );
+            }
 
+            throw ldapException;
+        }
+    }
+    
+    
     /**
-     * Performs a delete operation based on the delete request object.
+     * Performs an asynchronous delete operation based on the delete request object.
      *  
      * @param delRequest the delete operation's request
-     * @param listener the delete operation response listener
      * @return delete operation's response, null if a non-null listener value is provided
      * @throws LdapException If the DN is not valid or if the deletion failed
      */
-    public DeleteResponse delete( DeleteRequest delRequest, DeleteListener listener ) throws LdapException
+    public DeleteFuture deleteAsync( DeleteRequest delRequest ) throws LdapException
     {
         checkSession();
 
-        LdapMessageCodec deleteMessage = new LdapMessageCodec();
+        DelRequestCodec delReqCodec = new DelRequestCodec();
 
         int newId = messageId.incrementAndGet();
+        
         delRequest.setMessageId( newId );
-        deleteMessage.setMessageId( newId );
+        delReqCodec.setMessageId( newId );
 
-        DelRequestCodec delCodec = new DelRequestCodec();
-        delCodec.setEntry( delRequest.getTargetDn() );
+        delReqCodec.setEntry( delRequest.getTargetDn() );
+        setControls( delRequest.getControls(), delReqCodec );
 
-        deleteMessage.setProtocolOP( delCodec );
-        setControls( delRequest.getControls(), deleteMessage );
+        DeleteFuture deleteFuture = new DeleteFuture( this, newId );
+        addToFutureMap( newId, deleteFuture );
 
-        BlockingQueue<Response> deleteResponseQueue = new LinkedBlockingQueue<Response>();
-        respQueueMap.put( newId, deleteResponseQueue );
-
-        ResponseFuture deleteFuture = new ResponseFuture( deleteResponseQueue );
-        futureMap.put( newId, deleteFuture );
-

[... 464 lines stripped ...]


Mime
View raw message