You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2010/03/30 13:24:57 UTC

svn commit: r929088 [2/5] - in /directory/clients/ldap/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api: ./ listener/

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=929088&r1=929087&r2=929088&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 Tue Mar 30 11:24:56 2010
@@ -1,57 +1,11 @@
-/*
- *  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;
@@ -60,162 +14,27 @@ import org.apache.directory.ldap.client.
 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.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 LdapConnection extends IoHandlerAdapter
-{
-
-    /** logger for reporting errors that might not be handled properly upstream */
-    private static final Logger LOG = LoggerFactory.getLogger( LdapConnection.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;
-
-    // ~~~~~~~~~~~~~~~~~ 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";
 
+public interface LdapConnection
+{
 
     //--------------------------- Helper methods ---------------------------//
     /**
@@ -223,10 +42,7 @@ public class LdapConnection extends IoHa
      *
      * @return <code>true</code> if we are connected.
      */
-    public boolean isConnected()
-    {
-        return ( ldapSession != null ) && connected.get();
-    }
+    public abstract boolean isConnected();
 
 
     /**
@@ -234,350 +50,7 @@ public class LdapConnection extends IoHa
      *
      * @return <code>true</code> if we are connected.
      */
-    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() );
-        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 LdapConnection()
-    {
-        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 LdapConnection( 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 LdapConnection( 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 LdapConnection( 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 LdapConnection( 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 LdapConnection( 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 LdapConnection( String server, int port, boolean useSsl )
-    {
-        config.setUseSsl( useSsl );
-        config.setLdapPort( port );
-        config.setLdapHost( server );
-        messageId = new AtomicInteger();
-    }
+    public abstract boolean isAuthenticated();
 
 
     //-------------------------- The methods ---------------------------//
@@ -587,93 +60,7 @@ public class LdapConnection extends IoHa
      * @return <code>true</code> if the connection is established, false otherwise
      * @throws LdapException if some error has occured
      */
-    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;
-    }
+    public abstract boolean connect() throws LdapException, IOException;
 
 
     /**
@@ -682,28 +69,7 @@ public class LdapConnection extends IoHa
      * @return <code>true</code> if the connection is closed, false otherwise
      * @throws IOException if some I/O error occurs
      */
-    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;
-    }
+    public abstract boolean close() throws IOException;
 
 
     //------------------------ The LDAP operations ------------------------//
@@ -716,107 +82,7 @@ public class LdapConnection extends IoHa
      * @param entry The entry to add
      * @result the add operation's response 
      */
-    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 ) );
-    }
-
-
-    /**
-     * 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 null 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
-    {
-        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;
-        }
-    }
+    public abstract AddResponse add( Entry entry ) throws LdapException;
 
 
     /**
@@ -826,71 +92,17 @@ public class LdapConnection extends IoHa
      * @return the add operation's response
      * @throws LdapException
      */
-    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;
-    }
+    public abstract AddResponse add( AddRequest addRequest ) throws LdapException;
 
 
     /**
-     * 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 ------------------------//
-
-    /**
      * Abandons a request submitted to the server for performing a particular operation
      * 
      * The abandonRequest is always non-blocking, because no response is expected
      * 
      * @param messageId the ID of the request message sent to the server 
      */
-    public void abandon( int messageId )
-    {
-        AbandonRequest abandonRequest = new AbandonRequest();
-        abandonRequest.setAbandonedMessageId( messageId );
-
-        abandonInternal( abandonRequest );
-    }
+    public abstract void abandon( int messageId );
 
 
     /**
@@ -901,59 +113,7 @@ public class LdapConnection extends IoHa
      *  
      * @param abandonRequest the abandon operation's request
      */
-    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 );
-        }
-    }
+    public abstract void abandon( AbandonRequest abandonRequest );
 
 
     /**
@@ -961,35 +121,7 @@ public class LdapConnection extends IoHa
      *
      * @return The BindResponse LdapResponse 
      */
-    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 );
-    }
-
-
-    /**
-     * Anonymous asynchronous Bind on a server. 
-     *
-     * @return The BindFuture
-     */
-    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 );
-    }
+    public abstract BindResponse bind() throws LdapException, IOException;
 
 
     /**
@@ -1000,38 +132,7 @@ public class LdapConnection extends IoHa
      * @param credentials The password. It can't be null 
      * @return The BindResponse LdapResponse 
      */
-    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 );
-    }
-
-
-    /**
-     * 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 );
-        
-        // Create the BindRequest
-        BindRequest bindRequest = new BindRequest();
-        bindRequest.setName( name );
-        bindRequest.setCredentials( StringTools.getBytesUtf8( credentials ) );
-
-        return bindAsync( bindRequest );
-    }
+    public abstract BindResponse bind( String name, String credentials ) throws LdapException, IOException;
 
 
     /**
@@ -1042,54 +143,7 @@ public class LdapConnection extends IoHa
      * @param credentials The password. It can't be null 
      * @return The BindResponse LdapResponse 
      */
-    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 );
-    }
-
-
-    /**
-     * 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( 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 );
-    }
+    public abstract BindResponse bind( DN name, String credentials ) throws LdapException, IOException;
 
 
     /**
@@ -1099,262 +153,7 @@ public class LdapConnection extends IoHa
      * parameters 
      * @return A LdapResponse containing the result
      */
-    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;
-    }
-
-
-    /**
-     * Do an asynchronous bind, based on a BindRequest.
-     *
-     * @param bindRequest The BindRequest to send
-     * @return BindFuture A future
-     */
-    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;
-    }
+    public abstract BindResponse bind( BindRequest bindRequest ) throws LdapException, IOException;
 
 
     /**
@@ -1374,101 +173,8 @@ public class LdapConnection extends IoHa
      * @param scope The sarch scope : OBJECT, ONELEVEL or SUBTREE 
      * @return A cursor on the result. 
      */
-    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 );
-    }
-
-
-    /**
-     * Do an asynchronous 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 baseDn The base for the search. It must be a valid
-     * DN, and can't be emtpy
-     * @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 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 );
-    }
-
-
-    /**
-     * 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 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;
-
-    }
+    public abstract Cursor<SearchResponse> search( String baseDn, String filter, SearchScope scope,
+        String... attributes ) throws LdapException;
 
 
     /**
@@ -1478,14 +184,7 @@ public class LdapConnection extends IoHa
      * @return A {@link Cursor} containing Entries and Referencs
      * @throws LdapException @TODO
      */
-    public Cursor<SearchResponse> search( SearchRequest searchRequest ) throws LdapException
-    {
-        SearchFuture searchFuture = searchAsync( searchRequest );
-
-        long timeout = getTimeout( searchRequest.getTimeout() );
-        
-        return new SearchCursor( searchFuture, timeout, TimeUnit.MILLISECONDS );
-    }
+    public abstract Cursor<SearchResponse> search( SearchRequest searchRequest ) throws LdapException;
 
 
     //------------------------ The LDAP operations ------------------------//
@@ -1494,62 +193,7 @@ public class LdapConnection extends IoHa
     /**
      * UnBind from a server. this is a request which expect no response.
      */
-    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;
-    }
+    public abstract void unBind() throws Exception;
 
 
     /**
@@ -1558,409 +202,7 @@ public class LdapConnection extends IoHa
      *
      * @param timeOut The timeout, in milliseconds
      */
-    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() );
-        }
-    }
+    public abstract void setTimeOut( long timeOut );
 
 
     /**
@@ -1972,24 +214,7 @@ public class LdapConnection extends IoHa
      * @return the modify operation's response
      * @throws LdapException in case of modify operation failure or timeout happens
      */
-    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 );
-    }
+    public abstract ModifyResponse modify( Entry entry, ModificationOperation modOp ) throws LdapException;
 
 
     /**
@@ -2000,161 +225,27 @@ public class LdapConnection extends IoHa
      * @return the modify operation's r"esponse
      * @throws LdapException in case of modify operation failure or timeout happens
      */
-    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;
-        }
-    }
-
-
-    /**
-     * 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();
-
-        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;
-    }
+    public abstract ModifyResponse modify( ModifyRequest modRequest ) throws LdapException;
 
 
     /**
      * renames the given entryDn with new Rdn and deletes the old RDN.
      * @see #rename(String, String, boolean)
      */
-    public ModifyDnResponse rename( String entryDn, String newRdn ) throws LdapException
-    {
-        return rename( entryDn, newRdn, true );
-    }
+    public abstract ModifyDnResponse rename( String entryDn, String newRdn ) throws LdapException;
 
 
     /**
      * renames the given entryDn with new RDN and deletes the old RDN.
      * @see #rename(DN, RDN, boolean)
      */
-    public ModifyDnResponse rename( DN entryDn, RDN newRdn ) throws LdapException
-    {
-        return rename( entryDn, newRdn, true );
-    }
+    public abstract ModifyDnResponse rename( DN entryDn, RDN newRdn ) throws LdapException;
 
 
     /**
      * @see #rename(DN, RDN, 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 );
-        }
-    }
+    public abstract ModifyDnResponse rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException;
 
 
     /**
@@ -2168,32 +259,13 @@ public class LdapConnection extends IoHa
      * @return modifyDn operations response
      * @throws LdapException
      */
-    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 );
-    }
+    public abstract ModifyDnResponse rename( DN entryDn, RDN newRdn, boolean deleteOldRdn ) throws LdapException;
 
 
     /**
      * @see #move(DN, DN) 
      */
-    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 );
-        }
-    }
+    public abstract ModifyDnResponse move( String entryDn, String newSuperiorDn ) throws LdapException;
 
 
     /**
@@ -2204,88 +276,7 @@ public class LdapConnection extends IoHa
      * @return modifyDn operations response
      * @throws LdapException
      */
-    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 );
-    }
-
-
-    /**
-     * 
-     * 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 )
-        {
-            // 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;
-        }
-    }
+    public abstract ModifyDnResponse move( DN entryDn, DN newSuperiorDn ) throws LdapException;
 
 
     /**
@@ -2293,59 +284,10 @@ public class LdapConnection extends IoHa
      * performs the modifyDn operation based on the given ModifyDnRequest.
      *
      * @param modDnRequest the request
-     * @param listener callback listener which will be called after the operation is completed
      * @return modifyDn operations response, null if non-null listener is provided
      * @throws LdapException
      */
-    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;
-    }
+    public abstract ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException;
 
 
     /**
@@ -2354,20 +296,7 @@ public class LdapConnection extends IoHa
      * @param dn the target entry's DN as a String
      * @throws LdapException If the DN is not valid or if the deletion failed
      */
-    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 );
-        }
-    }
+    public abstract DeleteResponse delete( String dn ) throws LdapException;
 
 
     /**
@@ -2376,167 +305,7 @@ public class LdapConnection extends IoHa
      * @param dn the target entry's DN
      * @throws LdapException If the DN is not valid or if the deletion failed
      */
-    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

[... 870 lines stripped ...]