directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kayyag...@apache.org
Subject svn commit: r929088 [4/5] - in /directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api: ./ listener/
Date Tue, 30 Mar 2010 11:24:57 GMT
Added: directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
URL: http://svn.apache.org/viewvc/directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java?rev=929088&view=auto
==============================================================================
--- directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java (added)
+++ directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java Tue Mar 30 11:24:56 2010
@@ -0,0 +1,3130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.net.ssl.SSLContext;
+
+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.future.SearchFuture;
+import org.apache.directory.ldap.client.api.listener.DeleteListener;
+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;
+import org.apache.directory.ldap.client.api.message.AddResponse;
+import org.apache.directory.ldap.client.api.message.BindRequest;
+import org.apache.directory.ldap.client.api.message.BindResponse;
+import org.apache.directory.ldap.client.api.message.CompareRequest;
+import org.apache.directory.ldap.client.api.message.CompareResponse;
+import org.apache.directory.ldap.client.api.message.DeleteRequest;
+import org.apache.directory.ldap.client.api.message.DeleteResponse;
+import org.apache.directory.ldap.client.api.message.ExtendedIntermediateResponse;
+import org.apache.directory.ldap.client.api.message.ExtendedRequest;
+import org.apache.directory.ldap.client.api.message.ExtendedResponse;
+import org.apache.directory.ldap.client.api.message.IntermediateResponse;
+import org.apache.directory.ldap.client.api.message.LdapResult;
+import org.apache.directory.ldap.client.api.message.ModifyDnRequest;
+import org.apache.directory.ldap.client.api.message.ModifyDnResponse;
+import org.apache.directory.ldap.client.api.message.ModifyRequest;
+import org.apache.directory.ldap.client.api.message.ModifyResponse;
+import org.apache.directory.ldap.client.api.message.Referral;
+import org.apache.directory.ldap.client.api.message.Response;
+import org.apache.directory.ldap.client.api.message.SearchIntermediateResponse;
+import org.apache.directory.ldap.client.api.message.SearchRequest;
+import org.apache.directory.ldap.client.api.message.SearchResponse;
+import org.apache.directory.ldap.client.api.message.SearchResultDone;
+import org.apache.directory.ldap.client.api.message.SearchResultEntry;
+import org.apache.directory.ldap.client.api.message.SearchResultReference;
+import org.apache.directory.ldap.client.api.protocol.LdapProtocolCodecFactory;
+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.LdapMessageCodec;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.LdapResultCodec;
+import org.apache.directory.shared.ldap.codec.LdapTransformer;
+import org.apache.directory.shared.ldap.codec.abandon.AbandonRequestCodec;
+import org.apache.directory.shared.ldap.codec.add.AddRequestCodec;
+import org.apache.directory.shared.ldap.codec.add.AddResponseCodec;
+import org.apache.directory.shared.ldap.codec.bind.BindRequestCodec;
+import org.apache.directory.shared.ldap.codec.bind.BindResponseCodec;
+import org.apache.directory.shared.ldap.codec.bind.LdapAuthentication;
+import org.apache.directory.shared.ldap.codec.bind.SaslCredentials;
+import org.apache.directory.shared.ldap.codec.bind.SimpleAuthentication;
+import org.apache.directory.shared.ldap.codec.compare.CompareRequestCodec;
+import org.apache.directory.shared.ldap.codec.compare.CompareResponseCodec;
+import org.apache.directory.shared.ldap.codec.controls.ControlImpl;
+import org.apache.directory.shared.ldap.codec.del.DelRequestCodec;
+import org.apache.directory.shared.ldap.codec.del.DelResponseCodec;
+import org.apache.directory.shared.ldap.codec.extended.ExtendedRequestCodec;
+import org.apache.directory.shared.ldap.codec.extended.ExtendedResponseCodec;
+import org.apache.directory.shared.ldap.codec.intermediate.IntermediateResponseCodec;
+import org.apache.directory.shared.ldap.codec.modify.ModifyRequestCodec;
+import org.apache.directory.shared.ldap.codec.modify.ModifyResponseCodec;
+import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNRequestCodec;
+import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNResponseCodec;
+import org.apache.directory.shared.ldap.codec.search.Filter;
+import org.apache.directory.shared.ldap.codec.search.SearchRequestCodec;
+import org.apache.directory.shared.ldap.codec.search.SearchResultDoneCodec;
+import org.apache.directory.shared.ldap.codec.search.SearchResultEntryCodec;
+import org.apache.directory.shared.ldap.codec.search.SearchResultReferenceCodec;
+import org.apache.directory.shared.ldap.codec.unbind.UnBindRequestCodec;
+import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.cursor.Cursor;
+import org.apache.directory.shared.ldap.entry.DefaultServerEntry;
+import org.apache.directory.shared.ldap.entry.Entry;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.ModificationOperation;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
+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.AliasDerefMode;
+import org.apache.directory.shared.ldap.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.message.control.Control;
+import org.apache.directory.shared.ldap.name.DN;
+import org.apache.directory.shared.ldap.name.RDN;
+import org.apache.directory.shared.ldap.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schema.loader.ldif.JarLdifSchemaLoader;
+import org.apache.directory.shared.ldap.schema.manager.impl.DefaultSchemaManager;
+import org.apache.directory.shared.ldap.util.LdapURL;
+import org.apache.directory.shared.ldap.util.StringTools;
+import org.apache.mina.core.filterchain.IoFilter;
+import org.apache.mina.core.future.CloseFuture;
+import org.apache.mina.core.future.ConnectFuture;
+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.IoSession;
+import org.apache.mina.filter.codec.ProtocolCodecFilter;
+import org.apache.mina.filter.ssl.SslFilter;
+import org.apache.mina.transport.socket.nio.NioSocketConnector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * 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$
+ */
+public class LdapNetworkConnection extends IoHandlerAdapter implements LdapAsyncConnection
+{
+
+    /** logger for reporting errors that might not be handled properly upstream */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapNetworkConnection.class );
+
+    private static final String LDAP_RESPONSE = "LdapReponse";
+
+    /** The timeout used for response we are waiting for */
+    private long timeOut = LdapConnectionConfig.DEFAULT_TIMEOUT;
+
+    /** configuration object for the connection */
+    private LdapConnectionConfig config = new LdapConnectionConfig();
+
+    /** The connector open with the remote server */
+    private IoConnector connector;
+
+    /** A flag set to true when we used a local connector */
+    private boolean localConnector;
+
+    /** The Ldap codec */
+    private IoFilter ldapProtocolFilter = new ProtocolCodecFilter( new LdapProtocolCodecFactory() );
+
+    /**  
+     * The created session, created when we open a connection with
+     * the Ldap server.
+     */
+    private IoSession ldapSession;
+
+    /** A Message ID which is incremented for each operation */
+    private AtomicInteger messageId;
+
+    /** a map to hold the ResponseFutures for all operations */
+    private Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<Integer, ResponseFuture<? extends Response>>();
+
+    /** list of controls supported by the server */
+    private List<String> supportedControls;
+
+    /** The ROOT DSE entry */
+    private Entry rootDSE;
+    
+    /** A flag indicating that the BindRequest has been issued and successfully authenticated the user */
+    private AtomicBoolean authenticated = new AtomicBoolean( false );
+    
+    /** A flag indicating that the connection is connected or not */
+    private AtomicBoolean connected = new AtomicBoolean( false );
+    
+    /** the schema manager */
+    private SchemaManager schemaManager;
+
+    /** flag to make the the connection schema aware */
+    private boolean enableSchema;
+    // ~~~~~~~~~~~~~~~~~ common error messages ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    private static final String OPERATION_CANCELLED = "Operation would have been cancelled";
+
+    static final String TIME_OUT_ERROR = "TimeOut occured";
+
+    static final String NO_RESPONSE_ERROR = "The response queue has been emptied, no response was found.";
+
+    private static final String COMPARE_FAILED = "Failed to perform compare operation";
+
+
+    //--------------------------- Helper methods ---------------------------//
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#isConnected()
+     */
+    public boolean isConnected()
+    {
+        return ( ldapSession != null ) && connected.get();
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#isAuthenticated()
+     */
+    public boolean isAuthenticated()
+    {
+        return isConnected() && authenticated.get();
+    }
+
+
+    /**
+     * Check that a session is valid, ie we can send requests to the
+     * server
+     *
+     * @throws Exception If the session is not valid
+     */
+    private void checkSession() throws InvalidConnectionException
+    {
+        if ( ldapSession == null )
+        {
+            throw new InvalidConnectionException( "Cannot connect on the server, the connection is null" );
+        }
+
+        if ( !connected.get() )
+        {
+            throw new InvalidConnectionException( "Cannot connect on the server, the connection is invalid" );
+        }
+    }
+    
+    
+    private void addToFutureMap( int messageId, ResponseFuture<? extends Response> future )
+    {
+        LOG.debug( "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 )
+        {
+            LOG.debug( "Removing <" + messageId + ", " + future.getClass().getName() + ">" );
+        }
+        
+        return future;
+    }
+
+
+    private ResponseFuture<? extends Response> peekFromFutureMap( int messageId )
+    {
+        ResponseFuture<? extends Response> future = futureMap.get( messageId );
+        
+        // future can be null if there was a abandon operation on that messageId
+        if( future != null )
+        {
+            LOG.debug( "Getting <" + messageId + ", " + future.getClass().getName() + ">" );
+        }
+        
+        return future;
+    }
+
+
+    /**
+     * Return the response stored into the current session.
+     *
+     * @return The last request response
+     */
+    public LdapMessageCodec getResponse()
+    {
+        return ( LdapMessageCodec ) ldapSession.getAttribute( LDAP_RESPONSE );
+    }
+
+
+    /**
+     * Inject the client Controls into the message
+     */
+    private void setControls( Map<String, Control> controls, LdapMessageCodec message )
+    {
+        // Add the controls
+        if ( controls != null )
+        {
+            for ( Control control : controls.values() )
+            {
+                ControlImpl ctrl = new ControlImpl( control.getOid() );
+
+                ctrl.setValue( control.getValue() );
+
+                message.addControl( ctrl );
+            }
+        }
+    }
+
+
+    /**
+     * Get the smallest timeout from the client timeout and the connection
+     * timeout.
+     */
+    private long getTimeout( long clientTimeOut )
+    {
+        if ( clientTimeOut <= 0 )
+        {
+            return ( timeOut <= 0 ) ? Long.MAX_VALUE : timeOut;
+        }
+        else if ( timeOut <= 0 )
+        {
+            return clientTimeOut;
+        }
+        else
+        {
+            return timeOut < clientTimeOut ? timeOut : clientTimeOut;
+        }
+    }
+
+
+    /**
+     * Convert a BindResponseCodec to a BindResponse message
+     */
+    private BindResponse convert( BindResponseCodec bindResponseCodec )
+    {
+        BindResponse bindResponse = new BindResponse();
+
+        bindResponse.setMessageId( bindResponseCodec.getMessageId() );
+        bindResponse.setServerSaslCreds( bindResponseCodec.getServerSaslCreds() );
+        bindResponse.setLdapResult( convert( bindResponseCodec.getLdapResult() ) );
+
+        return bindResponse;
+    }
+
+
+    /**
+     * Convert a IntermediateResponseCodec to a IntermediateResponse message based on the ResponseFuture's type
+     */
+    private void setIResponse( IntermediateResponseCodec intermediateResponseCodec, ResponseFuture responseFuture ) throws Exception
+    {
+        IntermediateResponse intermediateResponse = null;
+
+        if( responseFuture instanceof SearchFuture )
+        {
+            intermediateResponse = new SearchIntermediateResponse();
+        }
+        else if( responseFuture instanceof ExtendedFuture )
+        {
+            intermediateResponse = new ExtendedIntermediateResponse();
+        }
+        else
+        {
+            // currently we only support IR for search and extended operations
+            throw new UnsupportedOperationException( "Unknown ResponseFuture type " + responseFuture.getClass().getName() );
+        }
+        
+        intermediateResponse.setResponseName( intermediateResponseCodec.getResponseName() );
+        intermediateResponse.setResponseValue( intermediateResponseCodec.getResponseValue() );
+
+        responseFuture.set( intermediateResponse );
+    }
+
+
+    /**
+     * Convert a LdapResultCodec to a LdapResult message
+     */
+    private LdapResult convert( LdapResultCodec ldapResultCodec )
+    {
+        LdapResult ldapResult = new LdapResult();
+
+        ldapResult.setErrorMessage( ldapResultCodec.getErrorMessage() );
+        ldapResult.setMatchedDn( ldapResultCodec.getMatchedDN() );
+
+        // Loop on the referrals
+        Referral referral = new Referral();
+
+        if ( ldapResultCodec.getReferrals() != null )
+        {
+            for ( LdapURL url : ldapResultCodec.getReferrals() )
+            {
+                referral.addLdapUrls( url );
+            }
+        }
+
+        ldapResult.setReferral( referral );
+        ldapResult.setResultCode( ldapResultCodec.getResultCode() );
+
+        return ldapResult;
+    }
+
+
+    /**
+     * Convert a SearchResultEntryCodec to a SearchResultEntry message
+     */
+    private SearchResultEntry convert( SearchResultEntryCodec searchEntryResultCodec )
+    {
+        SearchResultEntry searchResultEntry = new SearchResultEntry();
+
+        searchResultEntry.setMessageId( searchEntryResultCodec.getMessageId() );
+        if( schemaManager != null )
+        {
+            searchResultEntry.setEntry( new DefaultServerEntry( schemaManager, searchEntryResultCodec.getEntry() ) );
+        }
+        else
+        {
+            searchResultEntry.setEntry( searchEntryResultCodec.getEntry() );
+        }
+        addControls( searchEntryResultCodec, searchResultEntry );
+
+        return searchResultEntry;
+    }
+
+
+    /**
+     * Convert a SearchResultDoneCodec to a SearchResultDone message
+     */
+    private SearchResultDone convert( SearchResultDoneCodec searchResultDoneCodec )
+    {
+        SearchResultDone searchResultDone = new SearchResultDone();
+
+        searchResultDone.setMessageId( searchResultDoneCodec.getMessageId() );
+        searchResultDone.setLdapResult( convert( searchResultDoneCodec.getLdapResult() ) );
+        addControls( searchResultDoneCodec, searchResultDone );
+
+        return searchResultDone;
+    }
+
+
+    /**
+     * Convert a SearchResultReferenceCodec to a SearchResultReference message
+     */
+    private SearchResultReference convert( SearchResultReferenceCodec searchEntryReferenceCodec )
+    {
+        SearchResultReference searchResultReference = new SearchResultReference();
+
+        searchResultReference.setMessageId( searchEntryReferenceCodec.getMessageId() );
+
+        // Loop on the referrals
+        Referral referral = new Referral();
+
+        if ( searchEntryReferenceCodec.getSearchResultReferences() != null )
+        {
+            for ( LdapURL url : searchEntryReferenceCodec.getSearchResultReferences() )
+            {
+                referral.addLdapUrls( url );
+            }
+        }
+
+        searchResultReference.setReferral( referral );
+        addControls( searchEntryReferenceCodec, searchResultReference );
+
+        return searchResultReference;
+    }
+
+
+    //------------------------- The constructors --------------------------//
+    /**
+     * Create a new instance of a LdapConnection on localhost,
+     * port 389.
+     */
+    public LdapNetworkConnection()
+    {
+        config.setUseSsl( false );
+        config.setLdapPort( config.getDefaultLdapPort() );
+        config.setLdapHost( config.getDefaultLdapHost() );
+        messageId = new AtomicInteger( 0 );
+    }
+
+
+    /**
+     * 
+     * Creates a new instance of LdapConnection with the given connection configuration.
+     *
+     * @param config the configuration of the LdapConnection
+     */
+    public LdapNetworkConnection( LdapConnectionConfig config )
+    {
+        this.config = config;
+        messageId = new AtomicInteger( 0 );
+        
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on localhost,
+     * port 389 if the SSL flag is off, or 636 otherwise.
+     * 
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( boolean useSsl )
+    {
+        config.setUseSsl( useSsl );
+        config.setLdapPort( useSsl ? config.getDefaultLdapsPort() : config.getDefaultLdapPort() );
+        config.setLdapHost( config.getDefaultLdapHost() );
+        messageId = new AtomicInteger( 0 );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, using the default port (389).
+     *
+     * @param server The server we want to be connected to
+     */
+    public LdapNetworkConnection( String server )
+    {
+        config.setUseSsl( false );
+        config.setLdapPort( config.getDefaultLdapPort() );
+        config.setLdapHost( server );
+        messageId = new AtomicInteger( 0 );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, using the default port (389) if the SSL flag 
+     * is off, or 636 otherwise.
+     *
+     * @param server The server we want to be connected to
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( String server, boolean useSsl )
+    {
+        config.setUseSsl( useSsl );
+        config.setLdapPort( useSsl ? config.getDefaultLdapsPort() : config.getDefaultLdapPort() );
+        config.setLdapHost( server );
+        messageId = new AtomicInteger( 0 );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a 
+     * given server and a given port. We don't use ssl.
+     *
+     * @param server The server we want to be connected to
+     * @param port The port the server is listening to
+     */
+    public LdapNetworkConnection( String server, int port )
+    {
+        this( server, port, false );
+    }
+
+
+    /**
+     * Create a new instance of a LdapConnection on a given
+     * server, and a give port. We set the SSL flag accordingly
+     * to the last parameter.
+     *
+     * @param server The server we want to be connected to
+     * @param port The port the server is listening to
+     * @param useSsl A flag to tell if it's a SSL connection or not.
+     */
+    public LdapNetworkConnection( String server, int port, boolean useSsl )
+    {
+        config.setUseSsl( useSsl );
+        config.setLdapPort( port );
+        config.setLdapHost( server );
+        messageId = new AtomicInteger();
+    }
+
+
+    //-------------------------- The methods ---------------------------//
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#connect()
+     */
+    public boolean connect() throws LdapException, IOException
+    {
+        if ( ( ldapSession != null ) && connected.get() )
+        {
+            // No need to connect if we already have a connected session
+            return true;
+        }
+
+        // Create the connector if needed
+        if ( connector == null )
+        {
+            connector = new NioSocketConnector();
+            localConnector = true;
+
+            // Add the codec to the chain
+            connector.getFilterChain().addLast( "ldapCodec", ldapProtocolFilter );
+
+            // If we use SSL, we have to add the SslFilter to the chain
+            if ( config.isUseSsl() )
+            {
+                try
+                {
+                    SSLContext sslContext = SSLContext.getInstance( config.getSslProtocol() );
+                    sslContext.init( config.getKeyManagers(), config.getTrustManagers(), config.getSecureRandom() );
+
+                    SslFilter sslFilter = new SslFilter( sslContext );
+                    sslFilter.setUseClientMode( true );
+                    connector.getFilterChain().addFirst( "sslFilter", sslFilter );
+                }
+                catch ( Exception e )
+                {
+                    String msg = "Failed to initialize the SSL context";
+                    LOG.error( msg, e );
+                    throw new LdapException( msg, e );
+                }
+            }
+
+            // 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 OrderedThreadPoolExecutor( 10 ), IoEventType.MESSAGE_RECEIVED ) );*/
+
+            // Inject the protocolHandler
+            connector.setHandler( this );
+        }
+
+        // Build the connection address
+        SocketAddress address = new InetSocketAddress( config.getLdapHost(), config.getLdapPort() );
+
+        // And create the connection future
+        ConnectFuture connectionFuture = connector.connect( address );
+
+        // Wait until it's established
+        connectionFuture.awaitUninterruptibly();
+
+        if ( !connectionFuture.isConnected() )
+        {
+            // disposing connector if not connected
+            try
+            {
+                close();
+            }
+            catch ( IOException ioe )
+            {
+                // Nothing to do
+            }
+
+            return false;
+        }
+
+        // Get back the session
+        ldapSession = connectionFuture.getSession();
+        connected.set( true );
+
+        // And inject the current Ldap container into the session
+        IAsn1Container ldapMessageContainer = new LdapMessageContainer();
+
+        // Store the container into the session 
+        ldapSession.setAttribute( "LDAP-Container", ldapMessageContainer );
+        
+        // Initialize the MessageId 
+        messageId.set( 0 );
+
+        // And return
+        return true;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#close()
+     */
+    public boolean close() throws IOException
+    {
+        // Close the session
+        if ( ( ldapSession != null ) && connected.get() )
+        {
+            ldapSession.close( true );
+            connected.set( false );
+        }
+
+        // And close the connector if it has been created locally
+        if ( localConnector )
+        {
+            // Release the connector
+            connector.dispose();
+            connector = null;
+        }
+        
+        // Reset the messageId
+        messageId.set( 0 );
+
+        return true;
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Add operations                                                      //
+    //---------------------------------------------------------------------//
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#add(org.apache.directory.shared.ldap.entry.Entry)
+     */
+    public AddResponse add( Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            String msg = "Cannot add empty entry";
+            LOG.debug( msg );
+            throw new NullPointerException( msg );
+        }
+
+        return add( new AddRequest( entry ) );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#addAsync(org.apache.directory.shared.ldap.entry.Entry)
+     */
+    public AddFuture addAsync( Entry entry ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            String msg = "Cannot add null entry";
+            LOG.debug( msg );
+            throw new NullPointerException( msg );
+        }
+
+        return addAsync( new AddRequest( entry ) );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#add(org.apache.directory.ldap.client.api.message.AddRequest)
+     */
+    public AddResponse add( AddRequest addRequest ) throws LdapException
+    {
+        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 )
+        {
+            // 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;
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#addAsync(org.apache.directory.ldap.client.api.message.AddRequest)
+     */
+    public AddFuture addAsync( AddRequest addRequest ) throws LdapException
+    {
+        checkSession();
+
+        AddRequestCodec addReqCodec = new AddRequestCodec();
+
+        int newId = messageId.incrementAndGet();
+        
+        addRequest.setMessageId( newId );
+        addReqCodec.setMessageId( newId );
+
+        addReqCodec.setEntry( addRequest.getEntry() );
+        addReqCodec.setEntryDn( addRequest.getEntry().getDn() );
+        setControls( addRequest.getControls(), addReqCodec );
+
+        AddFuture addFuture = new AddFuture( this, newId );
+        addToFutureMap( newId, addFuture );
+
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( addReqCodec );
+
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Add failed : timeout occured" );
+
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        
+        // Ok, done return the future
+        return addFuture;
+    }
+
+
+    /**
+     * converts the AddResponseCodec to AddResponse.
+     */
+    private AddResponse convert( AddResponseCodec addRespCodec )
+    {
+        AddResponse addResponse = new AddResponse();
+
+        addResponse.setMessageId( addRespCodec.getMessageId() );
+        addResponse.setLdapResult( convert( addRespCodec.getLdapResult() ) );
+
+        return addResponse;
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#abandon(int)
+     */
+    public void abandon( int messageId )
+    {
+        AbandonRequest abandonRequest = new AbandonRequest();
+        abandonRequest.setAbandonedMessageId( messageId );
+
+        abandonInternal( abandonRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#abandon(org.apache.directory.ldap.client.api.message.AbandonRequest)
+     */
+    public void abandon( AbandonRequest abandonRequest )
+    {
+        abandonInternal( abandonRequest );
+    }
+
+
+    /**
+     * Internal AbandonRequest handling
+     */
+    private void abandonInternal( AbandonRequest abandonRequest )
+    {
+        // Create the inner abandonRequest
+        AbandonRequestCodec request = new AbandonRequestCodec();
+
+        // Todo : The Abandon messageID is always 0
+        int newId = messageId.incrementAndGet();
+        abandonRequest.setMessageId( newId );
+        request.setMessageId( newId );
+
+        // Inject the data into the request
+        request.setAbandonedMessageId( abandonRequest.getAbandonedMessageId() );
+
+        // Inject the controls
+        setControls( abandonRequest.getControls(), request );
+
+        LOG.debug( "-----------------------------------------------------------------" );
+        LOG.debug( "Sending request \n{}", request );
+
+        // Send the request to the server
+        ldapSession.write( request );
+
+        // remove the associated listener if any 
+        int abandonId = abandonRequest.getAbandonedMessageId();
+
+        ResponseFuture rf = getFromFutureMap( abandonId );
+
+        // 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
+        // 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 );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bind()
+     */
+    public BindResponse bind() throws LdapException, IOException
+    {
+        LOG.debug( "Anonymous Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setName( StringTools.EMPTY );
+        bindRequest.setCredentials( StringTools.EMPTY_BYTES );
+
+        return bind( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bindAsync()
+     */
+    public BindFuture bindAsync() throws LdapException, IOException
+    {
+        LOG.debug( "Anonymous Bind request" );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setName( StringTools.EMPTY );
+        bindRequest.setCredentials( StringTools.EMPTY_BYTES );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bind(java.lang.String, java.lang.String)
+     */
+    public BindResponse bind( String name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setName( name );
+        bindRequest.setCredentials( StringTools.getBytesUtf8( credentials ) );
+
+        return bind( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bindAsync(java.lang.String, java.lang.String)
+     */
+    public BindFuture bindAsync( String name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+        
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setName( name );
+        bindRequest.setCredentials( StringTools.getBytesUtf8( credentials ) );
+
+        return bindAsync( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bind(org.apache.directory.shared.ldap.name.DN, java.lang.String)
+     */
+    public BindResponse bind( DN name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setCredentials( StringTools.getBytesUtf8( credentials ) );
+
+        if ( name == null )
+        {
+            bindRequest.setName( StringTools.EMPTY );
+        }
+        else
+        {
+            bindRequest.setName( name.getName() );
+        }
+        
+        return bind( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bindAsync(org.apache.directory.shared.ldap.name.DN, java.lang.String)
+     */
+    public BindFuture bindAsync( DN name, String credentials ) throws LdapException, IOException
+    {
+        LOG.debug( "Bind request : {}", name );
+
+        // Create the BindRequest
+        BindRequest bindRequest = new BindRequest();
+        bindRequest.setCredentials( StringTools.getBytesUtf8( credentials ) );
+
+        if ( name == null )
+        {
+            bindRequest.setName( StringTools.EMPTY );
+        }
+        else
+        {
+            bindRequest.setName( name.getName() );
+        }
+        
+        return bindAsync( bindRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bind(org.apache.directory.ldap.client.api.message.BindRequest)
+     */
+    public BindResponse bind( BindRequest bindRequest ) throws LdapException, IOException
+    {
+        BindFuture bindFuture = bindAsync( bindRequest );
+
+        // Get the result from the future
+        try
+        {
+            // Read the response, waiting for it if not available immediately
+            long timeout = getTimeout( bindRequest.getTimeout() );
+
+            // 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.set( true );
+
+                // Everything is fine, return the response
+                LOG.debug( "Bind successful : {}", bindResponse );
+            }
+            else
+            {
+                // We have had an error
+                LOG.debug( "Bind failed : {}", bindResponse );
+            }
+
+            return bindResponse;
+        }
+        catch ( TimeoutException te )
+        {
+            // Send an abandon request
+            if ( !bindFuture.isCancelled() )
+            {
+                abandon( bindRequest.getMessageId() );
+            }
+
+            // We didn't received anything : this is an error
+            LOG.error( "Bind failed : timeout occured" );
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        catch ( Exception ie )
+        {
+            // 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 ( !bindFuture.isCancelled() )
+            {
+                abandon( bindRequest.getMessageId() );
+            }
+
+            throw ldapException;
+        }
+    }
+    
+    
+    /**
+     * Create a SearchRequestCodec ready to be sent.
+     */
+    private SearchRequestCodec createSearchMessage( SearchRequest searchRequest ) throws LdapException
+    {
+        // Create a new codec SearchRequest object
+        SearchRequestCodec request = new SearchRequestCodec();
+
+        // Creates the messageID and stores it into the 
+        // initial message and the transmitted message.
+        int newId = messageId.incrementAndGet();
+        searchRequest.setMessageId( newId );
+        request.setMessageId( newId );
+
+        // Set the name
+        try
+        {
+            DN dn = new DN( searchRequest.getBaseDn() );
+            request.setBaseObject( dn );
+        }
+        catch ( LdapInvalidDnException 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
+        {
+            DN dn = new DN( bindRequest.getName() );
+            bindRequestCodec.setName( dn );
+        }
+        catch ( LdapInvalidDnException ine )
+        {
+            String msg = "The given dn '" + bindRequest.getName() + "' is not valid";
+            LOG.error( msg );
+            LdapException ldapException = new LdapException( msg );
+            ldapException.initCause( ine );
+
+            throw ldapException;
+        }
+
+        // Set the credentials
+        LdapAuthentication authentication = null;
+
+        if ( bindRequest.isSimple() )
+        {
+            // Simple bind
+            authentication = new SimpleAuthentication();
+            ( ( SimpleAuthentication ) authentication ).setSimple( bindRequest.getCredentials() );
+        }
+        else
+        {
+            // SASL bind
+            authentication = new SaslCredentials();
+            ( ( SaslCredentials ) authentication ).setCredentials( bindRequest.getCredentials() );
+            ( ( SaslCredentials ) authentication ).setMechanism( bindRequest.getSaslMechanism() );
+        }
+
+        // The authentication
+        bindRequestCodec.setAuthentication( authentication );
+
+        // Add the controls
+        setControls( bindRequest.getControls(), bindRequestCodec );
+
+        return bindRequestCodec;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#bindAsync(org.apache.directory.ldap.client.api.message.BindRequest)
+     */
+    public BindFuture bindAsync( BindRequest bindRequest ) throws LdapException, IOException
+    {
+        // First switch to anonymous state
+        authenticated.set( false );
+        
+        // try to connect, if we aren't already connected.
+        connect();
+
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        // Create the new message and update the messageId
+        LdapMessageCodec bindMessage = createBindMessage( bindRequest );
+
+        int newId = bindMessage.getMessageId();
+
+        LOG.debug( "-----------------------------------------------------------------" );
+        LOG.debug( "Sending request \n{}", bindMessage );
+
+        // Create a future for this Bind operation
+        BindFuture bindFuture = new BindFuture( this, newId );
+
+        addToFutureMap( newId, bindFuture );
+
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( bindMessage );
+
+        // Wait for the message to be sent to the server
+        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;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#search(java.lang.String, java.lang.String, org.apache.directory.shared.ldap.filter.SearchScope, java.lang.String)
+     */
+    public Cursor<SearchResponse> search( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        // 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 );
+
+        // Process the request in blocking mode
+        return search( searchRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#searchAsync(java.lang.String, java.lang.String, org.apache.directory.shared.ldap.filter.SearchScope, java.lang.String)
+     */
+    public SearchFuture searchAsync( String baseDn, String filter, SearchScope scope, String... attributes )
+        throws LdapException
+    {
+        // 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 );
+
+        // Process the request in blocking mode
+        return searchAsync( searchRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#searchAsync(org.apache.directory.ldap.client.api.message.SearchRequest)
+     */
+    public SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException
+    {
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        // Create the server request
+        SearchRequestCodec request = createSearchMessage( searchRequest );
+
+        LOG.debug( "-----------------------------------------------------------------" );
+        LOG.debug( "Sending request \n{}", request );
+
+        SearchFuture searchFuture = new SearchFuture( this, request.getMessageId() );
+        addToFutureMap( request.getMessageId(), searchFuture );
+
+        // 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 ) ) ) 
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Search failed : timeout occured" );
+
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        
+        // Ok, done return the future
+        return searchFuture;
+
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#search(org.apache.directory.ldap.client.api.message.SearchRequest)
+     */
+    public Cursor<SearchResponse> search( SearchRequest searchRequest ) throws LdapException
+    {
+        SearchFuture searchFuture = searchAsync( searchRequest );
+
+        long timeout = getTimeout( searchRequest.getTimeout() );
+        
+        return new SearchCursor( searchFuture, timeout, TimeUnit.MILLISECONDS );
+    }
+
+
+    //------------------------ The LDAP operations ------------------------//
+    // Unbind operations                                                   //
+    //---------------------------------------------------------------------//
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#unBind()
+     */
+    public void unBind() throws Exception
+    {
+        // If the session has not been establish, or is closed, we get out immediately
+        checkSession();
+
+        // Create the UnbindRequest
+        UnBindRequestCodec unbindRequest = new UnBindRequestCodec();
+
+        // Creates the messageID and stores it into the 
+        // initial message and the transmitted message.
+        int newId = messageId.incrementAndGet();
+        unbindRequest.setMessageId( newId );
+
+        LOG.debug( "-----------------------------------------------------------------" );
+        LOG.debug( "Sending Unbind request \n{}", unbindRequest );
+
+        // Send the request to the server
+        WriteFuture unbindFuture = ldapSession.write( unbindRequest );
+
+        //LOG.debug( "waiting for unbindFuture" );
+        //unbindFuture.awaitUninterruptibly();
+        //LOG.debug( "unbindFuture done" );
+        
+        authenticated.set( false );
+
+        // clear the mappings
+        clearMaps();
+        
+        //  We now have to close the session
+        if ( ( ldapSession != null ) && connected.get() )
+        {
+            CloseFuture closeFuture = ldapSession.close( true );
+
+            LOG.debug( "waiting for closeFuture" );
+            closeFuture.awaitUninterruptibly();
+            LOG.debug( "closeFuture done" );
+            connected.set( false );
+        }
+        
+        // Last, not least, reset the MessageId value
+        messageId.set(0);
+
+        // And get out
+        LOG.debug( "Unbind successful" );
+    }
+
+
+    /**
+     * Set the connector to use.
+     *
+     * @param connector The connector to use
+     */
+    public void setConnector( IoConnector connector )
+    {
+        this.connector = connector;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#setTimeOut(long)
+     */
+    public void setTimeOut( long timeOut )
+    {
+        this.timeOut = timeOut;
+    }
+
+
+    /**
+     * Handle the incoming LDAP messages. This is where we feed the cursor for search 
+     * requests, or call the listener. 
+     */
+    public void messageReceived( IoSession session, Object message ) throws Exception
+    {
+        // Feed the response and store it into the session
+        LdapMessageCodec response = ( LdapMessageCodec ) message;
+        
+        LOG.debug( "-------> {} Message received <-------", response );
+
+        // this check is necessary to prevent adding an abandoned operation's
+        // result(s) to corresponding queue
+        ResponseFuture<? extends Response> responseFuture = peekFromFutureMap( response.getMessageId() );
+
+        if ( responseFuture == null )
+        {
+            LOG.info( "There is no future associated with the messageId {}, ignoring the message", response
+                .getMessageId() );
+            return;
+        }
+
+        int messageId = response.getMessageId();
+
+        switch ( response.getMessageType() )
+        {
+            case ADD_RESPONSE:
+                // Transform the response
+                AddResponseCodec addRespCodec = (AddResponseCodec)response;
+                addRespCodec.addControl( response.getCurrentControl() );
+                addRespCodec.setMessageId( messageId );
+
+                AddResponse addResponse = convert( addRespCodec );
+                
+                AddFuture addFuture = (AddFuture)responseFuture;
+
+                if ( addFuture == null )
+                {
+                    LOG.error( "AddFuture is null" );
+                    throw new LdapException( "AddFuture is null"  );
+                }
+                
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 BIND_RESPONSE:
+                // Transform the response
+                BindResponseCodec bindResponseCodec = (BindResponseCodec)response;
+                bindResponseCodec.setMessageId( messageId );
+                bindResponseCodec.addControl( response.getCurrentControl() );
+                BindResponse bindResponse = convert( bindResponseCodec );
+
+                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
+                if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
+                {
+                    authenticated.set( true );
+
+                    // Everything is fine, return the response
+                    LOG.debug( "Bind successful : {}", bindResponse );
+                }
+                else
+                {
+                    // We have had an error
+                    LOG.debug( "Bind failed : {}", bindResponse );
+                }
+
+                // Store the response into the future
+                bindFuture.set( bindResponse );
+
+                // Remove the future from the map
+                removeFromFutureMaps( messageId );
+
+                break;
+
+            case COMPARE_RESPONSE:
+                // Transform the response
+                CompareResponseCodec compResCodec = (CompareResponseCodec)response;
+                compResCodec.setMessageId( messageId );
+                compResCodec.addControl( response.getCurrentControl() );
+
+                CompareResponse compareResponse = convert( compResCodec );
+                
+                CompareFuture compareFuture = (CompareFuture)responseFuture;
+
+                if ( compareFuture == null )
+                {
+                    LOG.error( "CompareFuture is null" );
+                    throw new LdapException( "CompareFuture is null"  );
+                }
+                
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 DEL_RESPONSE:
+                // Transform the response
+                DelResponseCodec delRespCodec = (DelResponseCodec)response;
+                delRespCodec.addControl( response.getCurrentControl() );
+                delRespCodec.setMessageId( messageId );
+
+                DeleteResponse deleteResponse = convert( delRespCodec );
+                
+                DeleteFuture deleteFuture = (DeleteFuture)responseFuture;
+
+                if ( deleteFuture == null )
+                {
+                    LOG.error( "DeleteFuture is null" );
+                    throw new LdapException( "DeleteFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 EXTENDED_RESPONSE:
+                // Transform the response
+                ExtendedResponseCodec extResCodec = (ExtendedResponseCodec)response;
+                extResCodec.setMessageId( messageId );
+                extResCodec.addControl( response.getCurrentControl() );
+
+                ExtendedResponse extendedResponse = convert( extResCodec );
+
+                ExtendedFuture extendedFuture = (ExtendedFuture)responseFuture;
+
+                if ( extendedFuture == null )
+                {
+                    LOG.error( "ExtendedFuture is null" );
+                    throw new LdapException( "extendedFuture is null"  );
+                }
+
+                // remove the listener from the listener map
+                if ( LOG.isDebugEnabled() )
+                {
+                    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;
+
+            case INTERMEDIATE_RESPONSE:
+                IntermediateResponseCodec intermediateResponseCodec = (IntermediateResponseCodec)response;
+                intermediateResponseCodec.setMessageId( messageId );
+                intermediateResponseCodec.addControl( response.getCurrentControl() );
+
+                setIResponse( intermediateResponseCodec, responseFuture );
+                
+                break;
+
+            case MODIFY_RESPONSE:
+                // Transform the response
+                ModifyResponseCodec modRespCodec = (ModifyResponseCodec)response;
+                modRespCodec.setMessageId( messageId );
+                modRespCodec.addControl( response.getCurrentControl() );
+
+                ModifyResponse modifyResp = convert( modRespCodec );
+                
+                ModifyFuture modifyFuture = (ModifyFuture)responseFuture;
+
+                if ( modifyFuture == null )
+                {
+                    LOG.error( "ModifyFuture is null" );
+                    throw new LdapException( "ModifyFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 MODIFYDN_RESPONSE:
+                // Transform the response
+                ModifyDNResponseCodec modDnRespCodec = (ModifyDNResponseCodec)response;
+                modDnRespCodec.setMessageId( messageId );
+                modDnRespCodec.addControl( response.getCurrentControl() );
+
+                ModifyDnResponse modifyDnResp = convert( modDnRespCodec );
+                
+                ModifyDnFuture modifyDnFuture = (ModifyDnFuture)responseFuture;
+
+                if ( modifyDnFuture == null )
+                {
+                    LOG.error( "ModifyDNFuture is null" );
+                    throw new LdapException( "ModifyDNFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 SEARCH_RESULT_DONE:
+                // Store the response into the responseQueue
+                SearchResultDoneCodec searchResultDoneCodec = (SearchResultDoneCodec)response;
+                searchResultDoneCodec.setMessageId( messageId );
+                searchResultDoneCodec.addControl( response.getCurrentControl() );
+                SearchResultDone searchResultDone = convert( searchResultDoneCodec );
+
+                SearchFuture searchFuture = (SearchFuture)responseFuture;
+                
+                if ( searchFuture == null )
+                {
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    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 SEARCH_RESULT_ENTRY:
+                // Store the response into the responseQueue
+                SearchResultEntryCodec searchResultEntryCodec = (SearchResultEntryCodec)response;
+                searchResultEntryCodec.setMessageId( messageId );
+                searchResultEntryCodec.addControl( response.getCurrentControl() );
+
+                SearchResultEntry srchEntry = convert( searchResultEntryCodec );
+
+                searchFuture = (SearchFuture)responseFuture;
+                
+                if ( searchFuture == null )
+                {
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    LOG.debug( "Search entry found : {}", srchEntry );
+                }
+
+                // Store the response into the future
+                searchFuture.set( srchEntry );
+                
+                break;
+
+            case SEARCH_RESULT_REFERENCE:
+                // Store the response into the responseQueue
+                SearchResultReferenceCodec searchResultReferenceCodec = (SearchResultReferenceCodec)response;
+                searchResultReferenceCodec.setMessageId( messageId );
+                searchResultReferenceCodec.addControl( response.getCurrentControl() );
+
+                SearchResultReference searchResultReference = convert( searchResultReferenceCodec );
+
+                searchFuture = (SearchFuture)responseFuture;
+                
+                if ( searchFuture == null )
+                {
+                    LOG.error( "SearchFuture is null" );
+                    throw new LdapException( "SearchFuture is null"  );
+                }
+                
+                if ( LOG.isDebugEnabled() )
+                {
+                    LOG.debug( "Search reference found : {}", searchResultReference );
+                }
+
+                // Store the response into the future
+                searchFuture.set( searchResultReference );
+                
+                break;
+
+            default:
+                LOG.error( "~~~~~~~~~~~~~~~~~~~~~ Unknown message type {} ~~~~~~~~~~~~~~~~~~~~~", response
+                    .getMessageTypeName() );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#modify(org.apache.directory.shared.ldap.entry.Entry, org.apache.directory.shared.ldap.entry.ModificationOperation)
+     */
+    public ModifyResponse modify( Entry entry, ModificationOperation modOp ) throws LdapException
+    {
+        if ( entry == null )
+        {
+            LOG.debug( "received a null entry for modification" );
+            throw new NullPointerException( "Entry to be modified cannot be null" );
+        }
+
+        ModifyRequest modReq = new ModifyRequest( entry.getDn() );
+
+        Iterator<EntryAttribute> itr = entry.iterator();
+        while ( itr.hasNext() )
+        {
+            modReq.addModification( itr.next(), modOp );
+        }
+
+        return modify( modReq );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#modify(org.apache.directory.ldap.client.api.message.ModifyRequest)
+     */
+    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 )
+        {
+            // 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;
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#modifyAsync(org.apache.directory.ldap.client.api.message.ModifyRequest)
+     */
+    public ModifyFuture modifyAsync( ModifyRequest modRequest ) throws LdapException
+    {
+        checkSession();
+
+        ModifyRequestCodec modReqCodec = new ModifyRequestCodec();
+
+        int newId = messageId.incrementAndGet();
+        modRequest.setMessageId( newId );
+        modReqCodec.setMessageId( newId );
+
+        modReqCodec.setModifications( modRequest.getMods() );
+        modReqCodec.setObject( modRequest.getDn() );
+
+        setControls( modRequest.getControls(), modReqCodec );
+        
+        ModifyFuture modifyFuture = new ModifyFuture( this, newId );
+        addToFutureMap( newId, modifyFuture );
+
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( modReqCodec );
+
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
+
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        
+        // Ok, done return the future
+        return modifyFuture;
+    }
+
+
+    /**
+     * converts the ModifyResponseCodec to ModifyResponse.
+     */
+    private ModifyResponse convert( ModifyResponseCodec modRespCodec )
+    {
+        ModifyResponse modResponse = new ModifyResponse();
+
+        modResponse.setMessageId( modRespCodec.getMessageId() );
+        modResponse.setLdapResult( convert( modRespCodec.getLdapResult() ) );
+
+        return modResponse;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#rename(java.lang.String, java.lang.String)
+     */
+    public ModifyDnResponse rename( String entryDn, String newRdn ) throws LdapException
+    {
+        return rename( entryDn, newRdn, true );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#rename(org.apache.directory.shared.ldap.name.DN, org.apache.directory.shared.ldap.name.RDN)
+     */
+    public ModifyDnResponse rename( DN entryDn, RDN newRdn ) throws LdapException
+    {
+        return rename( entryDn, newRdn, true );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#rename(java.lang.String, java.lang.String, boolean)
+     */
+    public ModifyDnResponse rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        try
+        {
+            return rename( new DN( entryDn ), new RDN( newRdn ), deleteOldRdn );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#rename(org.apache.directory.shared.ldap.name.DN, org.apache.directory.shared.ldap.name.RDN, boolean)
+     */
+    public ModifyDnResponse rename( DN entryDn, RDN newRdn, boolean deleteOldRdn ) throws LdapException
+    {
+        ModifyDnRequest modDnRequest = new ModifyDnRequest();
+        modDnRequest.setEntryDn( entryDn );
+        modDnRequest.setNewRdn( newRdn );
+        modDnRequest.setDeleteOldRdn( deleteOldRdn );
+
+        return modifyDn( modDnRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#move(java.lang.String, java.lang.String)
+     */
+    public ModifyDnResponse move( String entryDn, String newSuperiorDn ) throws LdapException
+    {
+        try
+        {
+            return move( new DN( entryDn ), new DN( newSuperiorDn ) );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#move(org.apache.directory.shared.ldap.name.DN, org.apache.directory.shared.ldap.name.DN)
+     */
+    public ModifyDnResponse move( DN entryDn, DN newSuperiorDn ) throws LdapException
+    {
+        ModifyDnRequest modDnRequest = new ModifyDnRequest();
+        modDnRequest.setEntryDn( entryDn );
+        modDnRequest.setNewSuperior( newSuperiorDn );
+
+        //TODO not setting the below value is resulting in error
+        modDnRequest.setNewRdn( entryDn.getRdn() );
+
+        return modifyDn( modDnRequest );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#modifyDn(org.apache.directory.ldap.client.api.message.ModifyDnRequest)
+     */
+    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 )
+        {
+            // 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() );
+            }
+
+            throw ldapException;
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#modifyDnAsync(org.apache.directory.ldap.client.api.message.ModifyDnRequest)
+     */
+    public ModifyDnFuture modifyDnAsync( ModifyDnRequest modDnRequest ) throws LdapException
+    {
+        checkSession();
+
+        ModifyDNRequestCodec modDnCodec = new ModifyDNRequestCodec();
+
+        int newId = messageId.incrementAndGet();
+        modDnRequest.setMessageId( newId );
+        modDnCodec.setMessageId( newId );
+
+        modDnCodec.setEntry( modDnRequest.getEntryDn() );
+        modDnCodec.setNewRDN( modDnRequest.getNewRdn() );
+        modDnCodec.setDeleteOldRDN( modDnRequest.isDeleteOldRdn() );
+        modDnCodec.setNewSuperior( modDnRequest.getNewSuperior() );
+
+        setControls( modDnRequest.getControls(), modDnCodec );
+
+        ModifyDnFuture modifyDnFuture = new ModifyDnFuture( this, newId );
+        addToFutureMap( newId, modifyDnFuture );
+
+        // Send the request to the server
+        WriteFuture writeFuture = ldapSession.write( modDnCodec );
+
+        // Wait for the message to be sent to the server
+        if ( !writeFuture.awaitUninterruptibly( getTimeout( 0 ) ) ) 
+        {
+            // We didn't received anything : this is an error
+            LOG.error( "Modify failed : timeout occured" );
+
+            throw new LdapException( TIME_OUT_ERROR );
+        }
+        
+        // Ok, done return the future
+        return modifyDnFuture;
+    }
+
+
+    /**
+     * converts the ModifyDnResponseCodec to ModifyResponse.
+     */
+    private ModifyDnResponse convert( ModifyDNResponseCodec modDnRespCodec )
+    {
+        ModifyDnResponse modDnResponse = new ModifyDnResponse();
+
+        modDnResponse.setMessageId( modDnRespCodec.getMessageId() );
+        modDnResponse.setLdapResult( convert( modDnRespCodec.getLdapResult() ) );
+
+        return modDnResponse;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#delete(java.lang.String)
+     */
+    public DeleteResponse delete( String dn ) throws LdapException
+    {
+        try
+        {
+            DeleteRequest deleteRequest = new DeleteRequest( new DN( dn ) );
+
+            return delete( deleteRequest );
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#delete(org.apache.directory.shared.ldap.name.DN)
+     */
+    public DeleteResponse delete( DN dn ) throws LdapException
+    {
+        DeleteRequest deleteRequest = new DeleteRequest( dn );
+
+        return delete( deleteRequest );
+    }
+
+
+    /**
+     * deletes the entry with the given DN, and all its children
+     *  
+     * @param dn the target entry's DN
+     * @return operation's response
+     * @throws LdapException If the DN is not valid or if the deletion failed
+     */
+    public DeleteResponse deleteTree( DN dn ) throws LdapException
+    {
+        String treeDeleteOid = "1.2.840.113556.1.4.805";
+
+        if ( isControlSupported( treeDeleteOid ) )
+        {
+            DeleteRequest delRequest = new DeleteRequest( dn );
+            delRequest.add( new ControlImpl( treeDeleteOid ) );
+            return delete( delRequest );
+        }
+        else
+        {
+            String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n" +
+                " The deletion has been aborted";
+            LOG.error( msg );
+            throw new LdapException( msg );
+        }
+    }
+
+
+    /**
+     * deletes the entry with the given DN, and all its children
+     *  
+     * @param dn the target entry's DN as a String
+     * @return operation's response
+     * @throws LdapException If the DN is not valid or if the deletion failed
+     */
+    public DeleteResponse deleteTree( String dn ) throws LdapException
+    {
+        try
+        {
+            String treeDeleteOid = "1.2.840.113556.1.4.805";
+            DN newDn = new DN( dn );
+
+            if ( isControlSupported( treeDeleteOid ) )
+            {
+                DeleteRequest delRequest = new DeleteRequest( newDn );
+                delRequest.add( new ControlImpl( treeDeleteOid ) );
+                return delete( delRequest );
+            }
+            else
+            {
+                String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n" +
+                    " The deletion has been aborted";
+                LOG.error( msg );
+                throw new LdapException( msg );
+            }
+        }
+        catch ( LdapInvalidDnException e )
+        {
+            LOG.error( e.getMessage(), e );
+            throw new LdapException( e.getMessage(), e );
+        }
+    }
+
+
+    /**
+     * removes all child entries present under the given DN and finally the DN itself
+     * 
+     * Working:
+     *          This is a recursive function which maintains a Map<DN,Cursor>.
+     *          The way the cascade delete works is by checking for children for a 
+     *          given DN(i.e opening a search cursor) and if the cursor is empty
+     *          then delete the DN else for each entry's DN present in cursor call
+     *          deleteChildren() with the DN and the reference to the map.
+     *          
+     *          The reason for opening a search cursor is based on an assumption
+     *          that an entry *might* contain children, consider the below DIT fragment
+     *          
+     *          parent
+     *          /     \
+     *        child1   child2
+     *                 /     \
+     *               grand21  grand22
+     *               
+     *           The below method works better in the case where the tree depth is >1 
+     *          
+     *   In the case of passing a non-null DeleteListener, the return value will always be null, cause the
+     *   operation is treated as asynchronous and response result will be sent using the listener callback
+     *   
+     *  //FIXME provide another method for optimizing delete operation for a tree with depth <=1
+     *          
+     * @param dn the DN which will be removed after removing its children
+     * @param map a map to hold the Cursor related to a DN
+     * @param listener  the delete operation response listener 
+     * @throws LdapException If the DN is not valid or if the deletion failed
+     */
+    private DeleteResponse deleteRecursive( DN dn, Map<DN, Cursor<SearchResponse>> cursorMap,
+        DeleteListener listener ) throws LdapException
+    {
+        LOG.debug( "searching for {}", dn.getName() );
+        DeleteResponse delResponse = null;
+        Cursor<SearchResponse> cursor = null;
+
+        try
+        {
+            if ( cursorMap == null )
+            {
+                cursorMap = new HashMap<DN, Cursor<SearchResponse>>();
+            }
+
+            cursor = cursorMap.get( dn );
+
+            if ( cursor == null )
+            {
+                cursor = search( dn.getName(), "(objectClass=*)", SearchScope.ONELEVEL, ( String[] ) null );
+                LOG.debug( "putting cursor for {}", dn.getName() );
+                cursorMap.put( dn, cursor );
+            }
+
+            if ( !cursor.next() ) // if this is a leaf entry's DN
+            {
+                LOG.debug( "deleting {}", dn.getName() );
+                cursorMap.remove( dn );
+                cursor.close();
+                delResponse = delete( new DeleteRequest( dn ) );
+            }
+            else
+            {
+                do
+                {
+                    SearchResponse searchResp = cursor.get();
+
+                    if ( searchResp instanceof SearchResultEntry )
+                    {
+                        SearchResultEntry searchResult = ( SearchResultEntry ) searchResp;
+                        deleteRecursive( searchResult.getEntry().getDn(), cursorMap, listener );
+                    }
+                }
+                while ( cursor.next() );
+
+                cursorMap.remove( dn );
+                cursor.close();
+                LOG.debug( "deleting {}", dn.getName() );
+                delResponse = delete( new DeleteRequest( dn ) );
+            }
+        }
+        catch ( Exception e )
+        {
+            String msg = "Failed to delete child entries under the DN " + dn.getName();
+            LOG.error( msg, e );
+            throw new LdapException( msg, e );
+        }
+
+        return delResponse;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.directory.ldap.client.api.LdapConnection1#delete(org.apache.directory.ldap.client.api.message.DeleteRequest)
+     */
+    public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
+    {
+        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

[... 709 lines stripped ...]


Mime
View raw message