001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.server.ldap;
021
022
023import java.io.IOException;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.List;
030import java.util.Map;
031import java.util.Set;
032
033import javax.net.ssl.KeyManagerFactory;
034
035import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
036import org.apache.directory.api.ldap.model.constants.Loggers;
037import org.apache.directory.api.ldap.model.constants.SaslQoP;
038import org.apache.directory.api.ldap.model.exception.LdapConfigurationException;
039import org.apache.directory.api.ldap.model.exception.LdapException;
040import org.apache.directory.api.ldap.model.message.AbandonRequest;
041import org.apache.directory.api.ldap.model.message.AddRequest;
042import org.apache.directory.api.ldap.model.message.AddResponse;
043import org.apache.directory.api.ldap.model.message.BindRequest;
044import org.apache.directory.api.ldap.model.message.BindResponse;
045import org.apache.directory.api.ldap.model.message.CompareRequest;
046import org.apache.directory.api.ldap.model.message.CompareResponse;
047import org.apache.directory.api.ldap.model.message.DeleteRequest;
048import org.apache.directory.api.ldap.model.message.DeleteResponse;
049import org.apache.directory.api.ldap.model.message.ExtendedRequest;
050import org.apache.directory.api.ldap.model.message.ExtendedResponse;
051import org.apache.directory.api.ldap.model.message.IntermediateResponse;
052import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
053import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
054import org.apache.directory.api.ldap.model.message.ModifyRequest;
055import org.apache.directory.api.ldap.model.message.ModifyResponse;
056import org.apache.directory.api.ldap.model.message.SearchRequest;
057import org.apache.directory.api.ldap.model.message.SearchResultDone;
058import org.apache.directory.api.ldap.model.message.SearchResultEntry;
059import org.apache.directory.api.ldap.model.message.SearchResultReference;
060import org.apache.directory.api.ldap.model.message.UnbindRequest;
061import org.apache.directory.api.ldap.model.message.extended.NoticeOfDisconnect;
062import org.apache.directory.server.core.api.DirectoryService;
063import org.apache.directory.server.core.api.partition.PartitionNexus;
064import org.apache.directory.server.core.security.CertificateUtil;
065import org.apache.directory.server.i18n.I18n;
066import org.apache.directory.server.ldap.handlers.LdapRequestHandler;
067import org.apache.directory.server.ldap.handlers.LdapResponseHandler;
068import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler;
069import org.apache.directory.server.ldap.handlers.request.AbandonRequestHandler;
070import org.apache.directory.server.ldap.handlers.request.AddRequestHandler;
071import org.apache.directory.server.ldap.handlers.request.BindRequestHandler;
072import org.apache.directory.server.ldap.handlers.request.CompareRequestHandler;
073import org.apache.directory.server.ldap.handlers.request.DeleteRequestHandler;
074import org.apache.directory.server.ldap.handlers.request.ExtendedRequestHandler;
075import org.apache.directory.server.ldap.handlers.request.ModifyDnRequestHandler;
076import org.apache.directory.server.ldap.handlers.request.ModifyRequestHandler;
077import org.apache.directory.server.ldap.handlers.request.SearchRequestHandler;
078import org.apache.directory.server.ldap.handlers.request.UnbindRequestHandler;
079import org.apache.directory.server.ldap.handlers.response.AddResponseHandler;
080import org.apache.directory.server.ldap.handlers.response.BindResponseHandler;
081import org.apache.directory.server.ldap.handlers.response.CompareResponseHandler;
082import org.apache.directory.server.ldap.handlers.response.DeleteResponseHandler;
083import org.apache.directory.server.ldap.handlers.response.ExtendedResponseHandler;
084import org.apache.directory.server.ldap.handlers.response.IntermediateResponseHandler;
085import org.apache.directory.server.ldap.handlers.response.ModifyDnResponseHandler;
086import org.apache.directory.server.ldap.handlers.response.ModifyResponseHandler;
087import org.apache.directory.server.ldap.handlers.response.SearchResultDoneHandler;
088import org.apache.directory.server.ldap.handlers.response.SearchResultEntryHandler;
089import org.apache.directory.server.ldap.handlers.response.SearchResultReferenceHandler;
090import org.apache.directory.server.ldap.handlers.sasl.MechanismHandler;
091import org.apache.directory.server.ldap.handlers.ssl.LdapsInitializer;
092import org.apache.directory.server.ldap.replication.consumer.PingerThread;
093import org.apache.directory.server.ldap.replication.consumer.ReplicationConsumer;
094import org.apache.directory.server.ldap.replication.consumer.ReplicationStatusEnum;
095import org.apache.directory.server.ldap.replication.provider.ReplicationRequestHandler;
096import org.apache.directory.server.protocol.shared.DirectoryBackedService;
097import org.apache.directory.server.protocol.shared.transport.TcpTransport;
098import org.apache.directory.server.protocol.shared.transport.Transport;
099import org.apache.directory.server.protocol.shared.transport.UdpTransport;
100import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
101import org.apache.mina.core.filterchain.IoFilterChainBuilder;
102import org.apache.mina.core.future.WriteFuture;
103import org.apache.mina.core.service.IoHandler;
104import org.apache.mina.core.session.IoEventType;
105import org.apache.mina.core.session.IoSession;
106import org.apache.mina.filter.codec.ProtocolCodecFactory;
107import org.apache.mina.filter.codec.ProtocolCodecFilter;
108import org.apache.mina.filter.executor.ExecutorFilter;
109import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
110import org.apache.mina.handler.demux.MessageHandler;
111import org.apache.mina.transport.socket.AbstractSocketSessionConfig;
112import org.apache.mina.transport.socket.SocketAcceptor;
113import org.slf4j.Logger;
114import org.slf4j.LoggerFactory;
115import org.slf4j.MDC;
116
117
118/**
119 * An LDAP protocol provider implementation which dynamically associates
120 * handlers.
121 *
122 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
123 */
124public class LdapServer extends DirectoryBackedService
125{
126    /** logger for this class */
127    private static final Logger LOG = LoggerFactory.getLogger( LdapServer.class );
128
129    /** Logger for the replication consumer */
130    private static final Logger CONSUMER_LOG = LoggerFactory.getLogger( Loggers.CONSUMER_LOG.getName() );
131
132    /** Value (0) for configuration where size limit is unlimited. */
133    public static final long NO_SIZE_LIMIT = 0;
134
135    /** Value (0) for configuration where time limit is unlimited. */
136    public static final int NO_TIME_LIMIT = 0;
137
138    /** the constant service name of this ldap protocol provider **/
139    public static final String SERVICE_NAME = "ldap";
140
141    /** The default maximum size limit. */
142    private static final long MAX_SIZE_LIMIT_DEFAULT = 100;
143
144    /** The default maximum time limit. */
145    private static final int MAX_TIME_LIMIT_DEFAULT = 10000;
146
147    /** The default service pid. */
148    private static final String SERVICE_PID_DEFAULT = "org.apache.directory.server.ldap";
149
150    /** The default service name. */
151    private static final String SERVICE_NAME_DEFAULT = "ApacheDS LDAP Service";
152
153    /** the session manager for this LdapServer */
154    private LdapSessionManager ldapSessionManager = new LdapSessionManager();
155
156    /** a set of supported controls */
157    private Set<String> supportedControls;
158
159    /**
160     * The maximum size limit.
161     * @see {@link LdapServer#MAX_SIZE_LIMIT_DEFAULT }
162     */
163    private long maxSizeLimit = MAX_SIZE_LIMIT_DEFAULT;
164
165    /**
166     * The maximum time limit.
167     * @see {@link LdapServer#MAX_TIME_LIMIT_DEFAULT }
168     */
169    private int maxTimeLimit = MAX_TIME_LIMIT_DEFAULT;
170
171    /** The maximum size for an incoming PDU */
172    private int maxPDUSize = Integer.MAX_VALUE;
173
174    /** If LDAPS is activated : the external Keystore file, if defined */
175    private String keystoreFile;
176
177    /** If LDAPS is activated : the certificate password */
178    private String certificatePassword;
179
180    /** The extended operation handlers. */
181    private final Collection<ExtendedOperationHandler<? extends ExtendedRequest, ? extends ExtendedResponse>> extendedOperationHandlers =
182        new ArrayList<>();
183
184    /** The supported authentication mechanisms. */
185    private Map<String, MechanismHandler> saslMechanismHandlers = new HashMap<>();
186
187    /** The name of this host, validated during SASL negotiation. */
188    private String saslHost = "ldap.example.com";
189
190    /** The service principal, used by GSSAPI. */
191    private String saslPrincipal = "ldap/ldap.example.com@EXAMPLE.COM";
192
193    /** The quality of protection (QoP), used by DIGEST-MD5 and GSSAPI. */
194    private Set<String> saslQop;
195    private String saslQopString;
196
197    /** The list of realms serviced by this host. */
198    private List<String> saslRealms;
199
200    /** The protocol handlers */
201    // MessageReceived handlers
202    private LdapRequestHandler<AbandonRequest> abandonRequestHandler;
203    private LdapRequestHandler<AddRequest> addRequestHandler;
204    private LdapRequestHandler<BindRequest> bindRequestHandler;
205    private LdapRequestHandler<CompareRequest> compareRequestHandler;
206    private LdapRequestHandler<DeleteRequest> deleteRequestHandler;
207    private ExtendedRequestHandler extendedRequestHandler;
208    private LdapRequestHandler<ModifyRequest> modifyRequestHandler;
209    private LdapRequestHandler<ModifyDnRequest> modifyDnRequestHandler;
210    private LdapRequestHandler<SearchRequest> searchRequestHandler;
211    private LdapRequestHandler<UnbindRequest> unbindRequestHandler;
212
213    // MessageSent handlers
214    private LdapResponseHandler<AddResponse> addResponseHandler;
215    private LdapResponseHandler<BindResponse> bindResponseHandler;
216    private LdapResponseHandler<CompareResponse> compareResponseHandler;
217    private LdapResponseHandler<DeleteResponse> deleteResponseHandler;
218    private ExtendedResponseHandler extendedResponseHandler;
219    private LdapResponseHandler<ModifyResponse> modifyResponseHandler;
220    private LdapResponseHandler<IntermediateResponse> intermediateResponseHandler;
221    private LdapResponseHandler<ModifyDnResponse> modifyDnResponseHandler;
222    private LdapResponseHandler<SearchResultEntry> searchResultEntryHandler;
223    private LdapResponseHandler<SearchResultReference> searchResultReferenceHandler;
224    private LdapResponseHandler<SearchResultDone> searchResultDoneHandler;
225
226    /** the underlying provider codec factory */
227    private ProtocolCodecFactory codecFactory = LdapApiServiceFactory.getSingleton().getProtocolCodecFactory();
228
229    /** the MINA protocol handler */
230    private final LdapProtocolHandler handler = new LdapProtocolHandler( this );
231
232    /** tracks start state of the server */
233    private boolean started;
234
235    /**
236     * Whether or not confidentiality (TLS secured connection) is required:
237     * disabled by default.
238     */
239    private boolean confidentialityRequired;
240
241    private List<IoFilterChainBuilder> chainBuilders = new ArrayList<>();
242
243    /** The handler responsible for the replication */
244    private ReplicationRequestHandler replicationReqHandler;
245
246    /** The list of replication consumers */
247    private List<ReplicationConsumer> replConsumers;
248
249    private KeyManagerFactory keyManagerFactory;
250
251    /** the time interval between subsequent pings to each replication provider */
252    private int pingerSleepTime;
253
254    /**
255     * the list of cipher suites to be used in LDAPS and StartTLS
256     * @deprecated See the {@link TcpTransport} class that contains this list
257     **/
258    @Deprecated
259    private List<String> enabledCipherSuites = new ArrayList<>();
260
261
262    /**
263     * Creates an LDAP protocol provider.
264     */
265    public LdapServer()
266    {
267        super.setEnabled( true );
268        super.setServiceId( SERVICE_PID_DEFAULT );
269        super.setServiceName( SERVICE_NAME_DEFAULT );
270
271        saslQop = new HashSet<>();
272        saslQop.add( SaslQoP.AUTH.getValue() );
273        saslQop.add( SaslQoP.AUTH_INT.getValue() );
274        saslQop.add( SaslQoP.AUTH_CONF.getValue() );
275        saslQopString = SaslQoP.AUTH.getValue() + ',' + SaslQoP.AUTH_INT.getValue() + ','
276            + SaslQoP.AUTH_CONF.getValue();
277
278        saslRealms = new ArrayList<>();
279        saslRealms.add( "example.com" );
280
281        this.supportedControls = new HashSet<>();
282    }
283
284
285    /**
286     * Install the LDAP request handlers.
287     */
288    private void installDefaultHandlers()
289    {
290        if ( getAbandonRequestHandler() == null )
291        {
292            setAbandonHandler( new AbandonRequestHandler() );
293        }
294
295        if ( getAddRequestHandler() == null )
296        {
297            setAddHandlers( new AddRequestHandler(), new AddResponseHandler() );
298        }
299
300        if ( getBindRequestHandler() == null )
301        {
302            BindRequestHandler bindRequestHandler = new BindRequestHandler();
303            bindRequestHandler.setSaslMechanismHandlers( saslMechanismHandlers );
304
305            setBindHandlers( bindRequestHandler, new BindResponseHandler() );
306        }
307
308        if ( getCompareRequestHandler() == null )
309        {
310            setCompareHandlers( new CompareRequestHandler(), new CompareResponseHandler() );
311        }
312
313        if ( getDeleteRequestHandler() == null )
314        {
315            setDeleteHandlers( new DeleteRequestHandler(), new DeleteResponseHandler() );
316        }
317
318        if ( getExtendedRequestHandler() == null )
319        {
320            setExtendedHandlers( new ExtendedRequestHandler(), new ExtendedResponseHandler() );
321        }
322
323        if ( getIntermediateResponseHandler() == null )
324        {
325            setIntermediateHandler( new IntermediateResponseHandler() );
326        }
327
328        if ( getModifyRequestHandler() == null )
329        {
330            setModifyHandlers( new ModifyRequestHandler(), new ModifyResponseHandler() );
331        }
332
333        if ( getModifyDnRequestHandler() == null )
334        {
335            setModifyDnHandlers( new ModifyDnRequestHandler(), new ModifyDnResponseHandler() );
336        }
337
338        if ( getSearchRequestHandler() == null )
339        {
340            setSearchHandlers( new SearchRequestHandler(),
341                new SearchResultEntryHandler(),
342                new SearchResultReferenceHandler(),
343                new SearchResultDoneHandler() );
344        }
345
346        if ( getUnbindRequestHandler() == null )
347        {
348            setUnbindHandler( new UnbindRequestHandler() );
349        }
350    }
351
352
353    /**
354     * reloads the SSL context by replacing the existing SslFilter
355     * with a new SslFilter after reloading the keystore.
356     *
357     * Note: should be called to reload the keystore after changing the digital certificate.
358     * @throws Exception If teh SSLContext can't be reloaded
359     */
360    public void reloadSslContext() throws Exception
361    {
362        if ( !started )
363        {
364            return;
365        }
366
367        LOG.info( "reloading SSL context..." );
368
369        keyManagerFactory = CertificateUtil.loadKeyStore( keystoreFile, certificatePassword );
370
371        String sslFilterName = "sslFilter";
372
373        for ( IoFilterChainBuilder chainBuilder : chainBuilders )
374        {
375            DefaultIoFilterChainBuilder dfcb = ( ( DefaultIoFilterChainBuilder ) chainBuilder );
376
377            if ( dfcb.contains( sslFilterName ) )
378            {
379                // Get the TcpTransport
380                TcpTransport tcpTransport = null;
381
382                for ( Transport transport : getTransports() )
383                {
384                    if ( transport instanceof TcpTransport )
385                    {
386                        tcpTransport = ( TcpTransport ) transport;
387                        break;
388                    }
389                }
390
391                DefaultIoFilterChainBuilder newChain = ( DefaultIoFilterChainBuilder ) LdapsInitializer
392                    .init( this, tcpTransport );
393                dfcb.replace( sslFilterName, newChain.get( sslFilterName ) );
394                newChain = null;
395            }
396        }
397
398        StartTlsHandler handler = ( StartTlsHandler ) getExtendedOperationHandler( StartTlsHandler.EXTENSION_OID );
399
400        if ( handler != null )
401        {
402            handler.setLdapServer( this );
403        }
404
405        LOG.info( "reloaded SSL context successfully" );
406    }
407
408
409    /**
410     * @throws IOException if we cannot bind to the specified port
411     * @throws Exception if the LDAP server cannot be started
412     */
413    @Override
414    public void start() throws Exception
415    {
416        if ( !isEnabled() )
417        {
418            return;
419        }
420
421        keyManagerFactory = CertificateUtil.loadKeyStore( keystoreFile, certificatePassword );
422
423        /*
424         * The server is now initialized, we can
425         * install the default requests handlers, which need
426         * access to the DirectoryServer instance.
427         */
428        installDefaultHandlers();
429
430        PartitionNexus nexus = getDirectoryService().getPartitionNexus();
431
432        for ( ExtendedOperationHandler<? extends ExtendedRequest, ? extends ExtendedResponse> h : extendedOperationHandlers )
433        {
434            LOG.info( "Added Extended Request Handler: {}", h.getOid() );
435            h.setLdapServer( this );
436            nexus.registerSupportedExtensions( h.getExtensionOids() );
437        }
438
439        nexus.registerSupportedSaslMechanisms( saslMechanismHandlers.keySet() );
440
441        // Install the replication handler if we have one
442        startReplicationProducer();
443
444        for ( Transport transport : transports )
445        {
446            if ( !( transport instanceof TcpTransport ) )
447            {
448                LOG.warn( "Cannot listen on an UDP transport : {}", transport );
449                continue;
450            }
451
452            IoFilterChainBuilder chain;
453
454            if ( transport.isSSLEnabled() )
455            {
456                chain = LdapsInitializer.init( this, ( TcpTransport ) transport );
457            }
458            else
459            {
460                chain = new DefaultIoFilterChainBuilder();
461            }
462
463            // Inject the codec into the chain
464            ( ( DefaultIoFilterChainBuilder ) chain ).addLast( "codec", new ProtocolCodecFilter( this
465                .getProtocolCodecFactory() ) );
466
467            // Now inject an ExecutorFilter for the write operations
468            // We use the same number of thread than the number of IoProcessor
469            // (NOTE : this has to be double checked)
470            ( ( DefaultIoFilterChainBuilder ) chain ).addLast( "executor", new ExecutorFilter(
471                new UnorderedThreadPoolExecutor( transport.getNbThreads() ), IoEventType.MESSAGE_RECEIVED ) );
472
473            /*
474            // Trace all the incoming and outgoing message to the console
475            ( ( DefaultIoFilterChainBuilder ) chain ).addLast( "logger", new IoFilterAdapter()
476                {
477                    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception
478                    {
479                        System.out.println( ">>> Message received : " + message );
480                        nextFilter.messageReceived(session, message);
481                    }
482
483                    public void filterWrite(NextFilter nextFilter, IoSession session,
484                            WriteRequest writeRequest) throws Exception
485                    {
486                        System.out.println( "<<< Message sent : " + writeRequest.getMessage() );
487                        nextFilter.filterWrite(session, writeRequest);
488                    }
489                });
490            */
491
492            startNetwork( transport, chain );
493        }
494
495        // And start the replication consumers on this server
496        // these should be started only after starting the network see DIRSERVER-1894
497        startReplicationConsumers();
498
499        started = true;
500
501        LOG.info( "Ldap service started." );
502    }
503
504
505    /**
506     * Install the replication handler if we have one
507     */
508    public void startReplicationProducer()
509    {
510        if ( replicationReqHandler != null )
511        {
512            replicationReqHandler.start( this );
513            ( ( SearchRequestHandler ) getSearchRequestHandler() ).setReplicationReqHandler( replicationReqHandler );
514        }
515    }
516
517
518    /**
519     * {@inheritDoc}
520     */
521    @Override
522    public void stop()
523    {
524        try
525        {
526            for ( Transport transport : transports )
527            {
528                if ( !( transport instanceof TcpTransport ) )
529                {
530                    continue;
531                }
532
533                // we should unbind the service before we begin sending the notice
534                // of disconnect so new connections are not formed while we process
535                List<WriteFuture> writeFutures = new ArrayList<>();
536
537                // If the socket has already been unbound as with a successful
538                // GracefulShutdownRequest then this will complain that the service
539                // is not bound - this is ok because the GracefulShutdown has already
540                // sent notices to to the existing active sessions
541                List<IoSession> sessions;
542
543                try
544                {
545                    sessions = new ArrayList<>( getSocketAcceptor( transport ).getManagedSessions().values() );
546                }
547                catch ( IllegalArgumentException e )
548                {
549                    LOG.warn( "Seems like the LDAP service ({}) has already been unbound.", getPort() );
550                    return;
551                }
552
553                getSocketAcceptor( transport ).dispose();
554
555                if ( LOG.isInfoEnabled() )
556                {
557                    LOG.info( "Unbind of an LDAP service ({}) is complete.", getPort() );
558                    LOG.info( "Sending notice of disconnect to existing clients sessions." );
559                }
560
561                // Send Notification of Disconnection messages to all connected clients.
562                if ( sessions != null )
563                {
564                    for ( IoSession session : sessions )
565                    {
566                        writeFutures.add( session.write( NoticeOfDisconnect.UNAVAILABLE ) );
567                    }
568                }
569
570                // And close the connections when the NoDs are sent.
571                Iterator<IoSession> sessionIt = sessions.iterator();
572
573                for ( WriteFuture future : writeFutures )
574                {
575                    future.await( 1000L );
576                    sessionIt.next().closeNow();
577                }
578
579                if ( replicationReqHandler != null )
580                {
581                    replicationReqHandler.stop();
582                }
583            }
584
585            stopConsumers();
586        }
587        catch ( Exception e )
588        {
589            LOG.warn( "Failed to sent NoD.", e );
590        }
591
592        started = false;
593        LOG.info( "Ldap service stopped." );
594    }
595
596
597    private void startNetwork( Transport transport, IoFilterChainBuilder chainBuilder ) throws Exception
598    {
599        if ( transport.getBackLog() < 0 )
600        {
601            // Set the backlog to the default value when it's below 0
602            transport.setBackLog( 50 );
603        }
604
605        chainBuilders.add( chainBuilder );
606
607        try
608        {
609            SocketAcceptor acceptor = getSocketAcceptor( transport );
610
611            // Now, configure the acceptor
612            // Disable the disconnection of the clients on unbind
613            acceptor.setCloseOnDeactivation( false );
614
615            // No Nagle's algorithm
616            acceptor.getSessionConfig().setTcpNoDelay( true );
617
618            // Inject the chain
619            acceptor.setFilterChainBuilder( chainBuilder );
620
621            // Inject the protocol handler
622            acceptor.setHandler( getHandler() );
623
624            ( ( AbstractSocketSessionConfig ) acceptor.getSessionConfig() ).setReadBufferSize( 64 * 1024 );
625            ( ( AbstractSocketSessionConfig ) acceptor.getSessionConfig() ).setSendBufferSize( 64 * 1024 );
626
627            // Bind to the configured address
628            acceptor.bind();
629
630            // We are done !
631            started = true;
632
633            if ( LOG.isInfoEnabled() )
634            {
635                LOG.info( "Successful bind of an LDAP Service ({}) is completed.", transport.getPort() );
636            }
637        }
638        catch ( IOException e )
639        {
640            String msg = I18n.err( I18n.ERR_171, transport.getPort() );
641            LdapConfigurationException lce = new LdapConfigurationException( msg );
642            lce.setCause( e );
643            LOG.error( msg, e );
644            throw lce;
645        }
646    }
647
648
649    /**
650     * Starts the replication consumers
651     *
652     * @throws LdapException If the consumer can't be started
653     */
654    public void startReplicationConsumers() throws Exception
655    {
656        if ( ( replConsumers != null ) && !replConsumers.isEmpty() )
657        {
658            final PingerThread pingerThread = new PingerThread( pingerSleepTime );
659            pingerThread.start();
660
661            for ( final ReplicationConsumer consumer : replConsumers )
662            {
663                consumer.init( getDirectoryService() );
664
665                Runnable consumerTask = new Runnable()
666                {
667                    @Override
668                    public void run()
669                    {
670                        try
671                        {
672                            while ( true )
673                            {
674                                if ( CONSUMER_LOG.isDebugEnabled() )
675                                {
676                                    MDC.put( "Replica", consumer.getId() );
677                                }
678
679                                LOG.info( "starting the replication consumer with {}", consumer );
680                                CONSUMER_LOG.info( "starting the replication consumer with {}", consumer );
681                                boolean isConnected = consumer.connect( ReplicationConsumer.NOW );
682
683                                if ( isConnected )
684                                {
685                                    pingerThread.addConsumer( consumer );
686
687                                    // We are now connected, start the replication
688                                    ReplicationStatusEnum status = null;
689
690                                    do
691                                    {
692                                        status = consumer.startSync();
693                                    }
694                                    while ( status == ReplicationStatusEnum.REFRESH_REQUIRED );
695
696                                    if ( status == ReplicationStatusEnum.STOPPED )
697                                    {
698                                        // Exit the loop
699                                        break;
700                                    }
701                                }
702                            }
703                        }
704                        catch ( Exception e )
705                        {
706                            LOG.error( "Failed to start consumer {}", consumer );
707                            CONSUMER_LOG.error( "Failed to start consumer  {}", consumer );
708                            throw new RuntimeException( e );
709                        }
710                    }
711                };
712
713                Thread consumerThread = new Thread( consumerTask );
714                consumerThread.setDaemon( true );
715                consumerThread.start();
716            }
717        }
718    }
719
720
721    /**
722     * stops the replication consumers
723     */
724    private void stopConsumers()
725    {
726        if ( replConsumers != null )
727        {
728            for ( ReplicationConsumer consumer : replConsumers )
729            {
730                LOG.info( "stopping the consumer with id {}", consumer.getId() );
731                consumer.stop();
732            }
733        }
734    }
735
736
737    public String getName()
738    {
739        return SERVICE_NAME;
740    }
741
742
743    public IoHandler getHandler()
744    {
745        return handler;
746    }
747
748
749    public LdapSessionManager getLdapSessionManager()
750    {
751        return ldapSessionManager;
752    }
753
754
755    public ProtocolCodecFactory getProtocolCodecFactory()
756    {
757        return codecFactory;
758    }
759
760
761    // ------------------------------------------------------------------------
762    // Configuration Methods
763    // ------------------------------------------------------------------------
764
765    /**
766     * Registers the specified {@link ExtendedOperationHandler} to this
767     * protocol provider to provide a specific LDAP extended operation.
768     *
769     * @param eoh an extended operation handler
770     * @throws Exception on failure to add the handler
771     */
772    public void addExtendedOperationHandler( ExtendedOperationHandler<? extends ExtendedRequest,
773            ? extends ExtendedResponse> eoh ) throws LdapException
774    {
775        if ( started )
776        {
777            eoh.setLdapServer( this );
778            PartitionNexus nexus = getDirectoryService().getPartitionNexus();
779            nexus.registerSupportedExtensions( eoh.getExtensionOids() );
780        }
781        else
782        {
783            extendedOperationHandlers.add( eoh );
784        }
785    }
786
787
788    /**
789     * Deregister an {@link ExtendedOperationHandler} with the specified <tt>oid</tt>
790     * from this protocol provider.
791     *
792     * @param oid the numeric identifier for the extended operation associated with
793     * the handler to remove
794     */
795    public void removeExtendedOperationHandler( String oid )
796    {
797        // need to do something like this to make this work right
798        //            DefaultPartitionNexus nexus = getDirectoryService().getPartitionNexus();
799        //            nexus.unregisterSupportedExtensions( eoh.getExtensionOids() );
800
801        ExtendedOperationHandler<?, ?> handler = null;
802
803        for ( ExtendedOperationHandler<?, ?> extendedOperationHandler : extendedOperationHandlers )
804        {
805            if ( extendedOperationHandler.getOid().equals( oid ) )
806            {
807                handler = extendedOperationHandler;
808                break;
809            }
810        }
811
812        extendedOperationHandlers.remove( handler );
813    }
814
815
816    /**
817     * Returns an {@link ExtendedOperationHandler} with the specified <tt>oid</tt>
818     * which is registered to this protocol provider.
819     *
820     * @param oid the oid of the extended request of associated with the extended
821     * request handler
822     * @return the exnteded operation handler
823     */
824    public ExtendedOperationHandler<? extends ExtendedRequest, ? extends ExtendedResponse> getExtendedOperationHandler(
825        String oid )
826    {
827        for ( ExtendedOperationHandler<? extends ExtendedRequest, ? extends ExtendedResponse>
828                extendedOperationHandler : extendedOperationHandlers )
829        {
830            if ( extendedOperationHandler.getOid().equals( oid ) )
831            {
832                return extendedOperationHandler;
833            }
834        }
835
836        return null;
837    }
838
839
840    /**
841     * Sets the mode for this LdapServer to accept requests with or without a
842     * TLS secured connection via either StartTLS extended operations or using
843     * LDAPS.
844     *
845     * @param confidentialityRequired true to require confidentiality
846     */
847    public void setConfidentialityRequired( boolean confidentialityRequired )
848    {
849        this.confidentialityRequired = confidentialityRequired;
850    }
851
852
853    /**
854     * Gets whether or not TLS secured connections are required to perform
855     * operations on this LdapServer.
856     *
857     * @return true if TLS secured connections are required, false otherwise
858     */
859    public boolean isConfidentialityRequired()
860    {
861        return confidentialityRequired;
862    }
863
864
865    /**
866     * Returns <tt>true</tt> if LDAPS is enabled.
867     *
868     * @param transport The LDAP transport
869     * @return <tt>true</tt> if LDAPS is enabled.
870     */
871    public boolean isEnableLdaps( Transport transport )
872    {
873        return transport.isSSLEnabled();
874    }
875
876
877    /**
878     * Sets the maximum size limit in number of entries to return for search.
879     *
880     * @param maxSizeLimit the maximum number of entries to return for search
881     */
882    public void setMaxSizeLimit( long maxSizeLimit )
883    {
884        this.maxSizeLimit = maxSizeLimit;
885    }
886
887
888    /**
889     * Returns the maximum size limit in number of entries to return for search.
890     *
891     * @return The maximum size limit.
892     */
893    public long getMaxSizeLimit()
894    {
895        return maxSizeLimit;
896    }
897
898
899    /**
900     * Sets the maximum time limit in milliseconds to conduct a search.
901     *
902     * @param maxTimeLimit the maximum length of time in milliseconds for search
903     */
904    public void setMaxTimeLimit( int maxTimeLimit )
905    {
906        this.maxTimeLimit = maxTimeLimit; //TODO review the time parameters used all over the server and convert to seconds
907    }
908
909
910    /**
911     * Returns the maximum time limit in milliseconds to conduct a search.
912     *
913     * @return The maximum time limit in milliseconds for search
914     */
915    public int getMaxTimeLimit()
916    {
917        return maxTimeLimit;
918    }
919
920
921    /**
922     * Gets the {@link ExtendedOperationHandler}s.
923     *
924     * @return A collection of {@link ExtendedOperationHandler}s.
925     */
926    public Collection<ExtendedOperationHandler<? extends ExtendedRequest, ? extends ExtendedResponse>> getExtendedOperationHandlers()
927    {
928        return new ArrayList<>(
929            extendedOperationHandlers );
930    }
931
932
933    /**
934     * Sets the {@link ExtendedOperationHandler}s.
935     *
936     * @param handlers A collection of {@link ExtendedOperationHandler}s.
937     */
938    public void setExtendedOperationHandlers(
939        Collection<ExtendedOperationHandler<ExtendedRequest, ExtendedResponse>> handlers )
940    {
941        this.extendedOperationHandlers.clear();
942        this.extendedOperationHandlers.addAll( handlers );
943    }
944
945
946    /**
947     * Returns the FQDN of this SASL host, validated during SASL negotiation.
948     *
949     * @return The FQDN of this SASL host, validated during SASL negotiation.
950     */
951    public String getSaslHost()
952    {
953        return saslHost;
954    }
955
956
957    /**
958     * Sets the FQDN of this SASL host, validated during SASL negotiation.
959     *
960     * @param saslHost The FQDN of this SASL host, validated during SASL negotiation.
961     */
962    public void setSaslHost( String saslHost )
963    {
964        this.saslHost = saslHost;
965    }
966
967
968    /**
969     * Returns the Kerberos principal name for this LDAP service, used by GSSAPI.
970     *
971     * @return The Kerberos principal name for this LDAP service, used by GSSAPI.
972     */
973    public String getSaslPrincipal()
974    {
975        return saslPrincipal;
976    }
977
978
979    /**
980     * Sets the Kerberos principal name for this LDAP service, used by GSSAPI.
981     *
982     * @param saslPrincipal The Kerberos principal name for this LDAP service, used by GSSAPI.
983     */
984    public void setSaslPrincipal( String saslPrincipal )
985    {
986        this.saslPrincipal = saslPrincipal;
987    }
988
989
990    /**
991     * Returns the quality-of-protection, used by DIGEST-MD5 and GSSAPI.
992     *
993     * @return The quality-of-protection, used by DIGEST-MD5 and GSSAPI.
994     */
995    public String getSaslQopString()
996    {
997        return saslQopString;
998    }
999
1000
1001    /**
1002     * Returns the Set of quality-of-protection, used by DIGEST-MD5 and GSSAPI.
1003     *
1004     * @return The quality-of-protection, used by DIGEST-MD5 and GSSAPI.
1005     */
1006    public Set<String> getSaslQop()
1007    {
1008        return saslQop;
1009    }
1010
1011
1012    /**
1013     * Returns the realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
1014     *
1015     * @return The realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
1016     */
1017    public List<String> getSaslRealms()
1018    {
1019        return saslRealms;
1020    }
1021
1022
1023    /**
1024     * Sets the realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
1025     *
1026    * @param saslRealms The realms serviced by this SASL host, used by DIGEST-MD5 and GSSAPI.
1027     */
1028    public void setSaslRealms( List<String> saslRealms )
1029    {
1030        this.saslRealms = saslRealms;
1031    }
1032
1033
1034    /**
1035     * @return the supported SASL mechanisms
1036     */
1037    public Map<String, MechanismHandler> getSaslMechanismHandlers()
1038    {
1039        return saslMechanismHandlers;
1040    }
1041
1042
1043    public void setSaslMechanismHandlers( Map<String, MechanismHandler> saslMechanismHandlers )
1044    {
1045        this.saslMechanismHandlers = saslMechanismHandlers;
1046    }
1047
1048
1049    public MechanismHandler addSaslMechanismHandler( String mechanism, MechanismHandler handler )
1050    {
1051        return this.saslMechanismHandlers.put( mechanism, handler );
1052    }
1053
1054
1055    public MechanismHandler removeSaslMechanismHandler( String mechanism )
1056    {
1057        return this.saslMechanismHandlers.remove( mechanism );
1058    }
1059
1060
1061    public MechanismHandler getMechanismHandler( String mechanism )
1062    {
1063        return this.saslMechanismHandlers.get( mechanism );
1064    }
1065
1066
1067    public Set<String> getSupportedMechanisms()
1068    {
1069        return saslMechanismHandlers.keySet();
1070    }
1071
1072
1073    @Override
1074    public void setDirectoryService( DirectoryService directoryService )
1075    {
1076        super.setDirectoryService( directoryService );
1077        Iterator<String> itr = directoryService.getLdapCodecService().registeredRequestControls();
1078
1079        while ( itr.hasNext() )
1080        {
1081            supportedControls.add( itr.next() );
1082        }
1083
1084        itr = directoryService.getLdapCodecService().registeredResponseControls();
1085
1086        while ( itr.hasNext() )
1087        {
1088            supportedControls.add( itr.next() );
1089        }
1090    }
1091
1092
1093    public Set<String> getSupportedControls()
1094    {
1095        return supportedControls;
1096    }
1097
1098
1099    /**
1100     * @return The MessageReceived handler for the AbandonRequest
1101     */
1102    public MessageHandler<AbandonRequest> getAbandonRequestHandler()
1103    {
1104        return abandonRequestHandler;
1105    }
1106
1107
1108    /**
1109     * Inject the MessageReceived handler into the IoHandler
1110     *
1111     * @param abandonRequestdHandler The AbandonRequest message received handler
1112     */
1113    public void setAbandonHandler( LdapRequestHandler<AbandonRequest> abandonRequestdHandler )
1114    {
1115        this.handler.removeReceivedMessageHandler( AbandonRequest.class );
1116        this.abandonRequestHandler = abandonRequestdHandler;
1117        this.abandonRequestHandler.setLdapServer( this );
1118        this.handler.addReceivedMessageHandler( AbandonRequest.class, this.abandonRequestHandler );
1119    }
1120
1121
1122    /**
1123     * @return The MessageReceived handler for the AddRequest
1124     */
1125    public LdapRequestHandler<AddRequest> getAddRequestHandler()
1126    {
1127        return addRequestHandler;
1128    }
1129
1130
1131    /**
1132     * @return The MessageSent handler for the AddResponse
1133     */
1134    public LdapResponseHandler<AddResponse> getAddResponseHandler()
1135    {
1136        return addResponseHandler;
1137    }
1138
1139
1140    /**
1141     * Inject the MessageReceived and MessageSent handler into the IoHandler
1142     *
1143     * @param addRequestHandler The AddRequest message received handler
1144     * @param addResponseHandler The AddResponse message sent handler
1145     */
1146    public void setAddHandlers( LdapRequestHandler<AddRequest> addRequestHandler,
1147        LdapResponseHandler<AddResponse> addResponseHandler )
1148    {
1149        this.handler.removeReceivedMessageHandler( AddRequest.class );
1150        this.addRequestHandler = addRequestHandler;
1151        this.addRequestHandler.setLdapServer( this );
1152        this.handler.addReceivedMessageHandler( AddRequest.class, this.addRequestHandler );
1153
1154        this.handler.removeSentMessageHandler( AddResponse.class );
1155        this.addResponseHandler = addResponseHandler;
1156        this.addResponseHandler.setLdapServer( this );
1157        this.handler.addSentMessageHandler( AddResponse.class, this.addResponseHandler );
1158    }
1159
1160
1161    /**
1162     * @return The MessageReceived handler for the BindRequest
1163     */
1164    public LdapRequestHandler<BindRequest> getBindRequestHandler()
1165    {
1166        return bindRequestHandler;
1167    }
1168
1169
1170    /**
1171     * @return The MessageSent handler for the BindResponse
1172     */
1173    public LdapResponseHandler<BindResponse> getBindResponseHandler()
1174    {
1175        return bindResponseHandler;
1176    }
1177
1178
1179    /**
1180     * Inject the MessageReceived and MessageSent handler into the IoHandler
1181     *
1182     * @param bindRequestHandler The BindRequest message received handler
1183     * @param bindResponseHandler The BindResponse message sent handler
1184     */
1185    public void setBindHandlers( LdapRequestHandler<BindRequest> bindRequestHandler,
1186        LdapResponseHandler<BindResponse> bindResponseHandler )
1187    {
1188        handler.removeReceivedMessageHandler( BindRequest.class );
1189        this.bindRequestHandler = bindRequestHandler;
1190        this.bindRequestHandler.setLdapServer( this );
1191        handler.addReceivedMessageHandler( BindRequest.class, this.bindRequestHandler );
1192
1193        handler.removeSentMessageHandler( BindResponse.class );
1194        this.bindResponseHandler = bindResponseHandler;
1195        this.bindResponseHandler.setLdapServer( this );
1196        handler.addSentMessageHandler( BindResponse.class, this.bindResponseHandler );
1197    }
1198
1199
1200    /**
1201     * @return The MessageReceived handler for the CompareRequest
1202     */
1203    public LdapRequestHandler<CompareRequest> getCompareRequestHandler()
1204    {
1205        return compareRequestHandler;
1206    }
1207
1208
1209    /**
1210     * @return The MessageSent handler for the CompareResponse
1211     */
1212    public LdapResponseHandler<CompareResponse> getCompareResponseHandler()
1213    {
1214        return compareResponseHandler;
1215    }
1216
1217
1218    /**
1219     * Inject the MessageReceived and MessageSent handler into the IoHandler
1220     *
1221     * @param compareRequestHandler The CompareRequest message received handler
1222     * @param compareResponseHandler The CompareResponse message sent handler
1223     */
1224    public void setCompareHandlers( LdapRequestHandler<CompareRequest> compareRequestHandler,
1225        LdapResponseHandler<CompareResponse> compareResponseHandler )
1226    {
1227        handler.removeReceivedMessageHandler( CompareRequest.class );
1228        this.compareRequestHandler = compareRequestHandler;
1229        this.compareRequestHandler.setLdapServer( this );
1230        this.handler.addReceivedMessageHandler( CompareRequest.class, this.compareRequestHandler );
1231
1232        handler.removeReceivedMessageHandler( CompareResponse.class );
1233        this.compareResponseHandler = compareResponseHandler;
1234        this.compareResponseHandler.setLdapServer( this );
1235        this.handler.addSentMessageHandler( CompareResponse.class, this.compareResponseHandler );
1236    }
1237
1238
1239    /**
1240     * @return The MessageReceived handler for the DeleteRequest
1241     */
1242    public LdapRequestHandler<DeleteRequest> getDeleteRequestHandler()
1243    {
1244        return deleteRequestHandler;
1245    }
1246
1247
1248    /**
1249     * @return The MessageSent handler for the DeleteResponse
1250     */
1251    public LdapResponseHandler<DeleteResponse> getDeleteResponseHandler()
1252    {
1253        return deleteResponseHandler;
1254    }
1255
1256
1257    /**
1258     * Inject the MessageReceived and MessageSent handler into the IoHandler
1259     *
1260     * @param deleteRequestHandler The DeleteRequest message received handler
1261     * @param deleteResponseHandler The DeleteResponse message sent handler
1262     */
1263    public void setDeleteHandlers( LdapRequestHandler<DeleteRequest> deleteRequestHandler,
1264        LdapResponseHandler<DeleteResponse> deleteResponseHandler )
1265    {
1266        handler.removeReceivedMessageHandler( DeleteRequest.class );
1267        this.deleteRequestHandler = deleteRequestHandler;
1268        this.deleteRequestHandler.setLdapServer( this );
1269        this.handler.addReceivedMessageHandler( DeleteRequest.class, this.deleteRequestHandler );
1270
1271        handler.removeSentMessageHandler( DeleteResponse.class );
1272        this.deleteResponseHandler = deleteResponseHandler;
1273        this.deleteResponseHandler.setLdapServer( this );
1274        this.handler.addSentMessageHandler( DeleteResponse.class, this.deleteResponseHandler );
1275    }
1276
1277
1278    /**
1279     * @return The MessageReceived handler for the ExtendedRequest
1280     */
1281    public LdapRequestHandler<ExtendedRequest> getExtendedRequestHandler()
1282    {
1283        return extendedRequestHandler;
1284    }
1285
1286
1287    /**
1288     * @return The MessageSent handler for the ExtendedResponse
1289     */
1290    public LdapResponseHandler<ExtendedResponse> getExtendedResponseHandler()
1291    {
1292        return extendedResponseHandler;
1293    }
1294
1295
1296    /**
1297     * Inject the MessageReceived and MessageSent handler into the IoHandler
1298     *
1299     * @param extendedRequestHandler The ExtendedRequest message received handler
1300     * @param extendedResponseHandler The ExtendedResponse message sent handler
1301     */
1302    @SuppressWarnings(
1303        { "unchecked", "rawtypes" })
1304    public void setExtendedHandlers( ExtendedRequestHandler extendedRequestHandler,
1305        ExtendedResponseHandler extendedResponseHandler )
1306    {
1307        handler.removeReceivedMessageHandler( ExtendedRequest.class );
1308        this.extendedRequestHandler = extendedRequestHandler;
1309        this.extendedRequestHandler.setLdapServer( this );
1310        this.handler.addReceivedMessageHandler( ExtendedRequest.class,
1311            this.extendedRequestHandler );
1312
1313        handler.removeSentMessageHandler( ExtendedResponse.class );
1314        this.extendedResponseHandler = extendedResponseHandler;
1315        this.extendedResponseHandler.setLdapServer( this );
1316        this.handler.addSentMessageHandler( ExtendedResponse.class, this.extendedResponseHandler );
1317    }
1318
1319
1320    /**
1321     * @return The MessageSent handler for the IntermediateResponse
1322     */
1323    public LdapResponseHandler<IntermediateResponse> getIntermediateResponseHandler()
1324    {
1325        return intermediateResponseHandler;
1326    }
1327
1328
1329    /**
1330     * Inject the MessageReceived and MessageSent handler into the IoHandler
1331     *
1332     * @param intermediateResponseHandler The IntermediateResponse message sent handler
1333     */
1334    public void setIntermediateHandler( LdapResponseHandler<IntermediateResponse> intermediateResponseHandler )
1335    {
1336        handler.removeSentMessageHandler( IntermediateResponse.class );
1337        this.intermediateResponseHandler = intermediateResponseHandler;
1338        this.intermediateResponseHandler.setLdapServer( this );
1339        this.handler.addSentMessageHandler( IntermediateResponse.class, this.intermediateResponseHandler );
1340    }
1341
1342
1343    /**
1344     * @return The MessageReceived handler for the ModifyRequest
1345     */
1346    public LdapRequestHandler<ModifyRequest> getModifyRequestHandler()
1347    {
1348        return modifyRequestHandler;
1349    }
1350
1351
1352    /**
1353     * @return The MessageSent handler for the ModifyResponse
1354     */
1355    public LdapResponseHandler<ModifyResponse> getModifyResponseHandler()
1356    {
1357        return modifyResponseHandler;
1358    }
1359
1360
1361    /**
1362     * Inject the MessageReceived and MessageSent handler into the IoHandler
1363     *
1364     * @param modifyRequestHandler The ModifyRequest message received handler
1365     * @param modifyResponseHandler The ModifyResponse message sent handler
1366     */
1367    public void setModifyHandlers( LdapRequestHandler<ModifyRequest> modifyRequestHandler,
1368        LdapResponseHandler<ModifyResponse> modifyResponseHandler )
1369    {
1370        handler.removeReceivedMessageHandler( ModifyRequest.class );
1371        this.modifyRequestHandler = modifyRequestHandler;
1372        this.modifyRequestHandler.setLdapServer( this );
1373        this.handler.addReceivedMessageHandler( ModifyRequest.class, this.modifyRequestHandler );
1374
1375        handler.removeSentMessageHandler( ModifyResponse.class );
1376        this.modifyResponseHandler = modifyResponseHandler;
1377        this.modifyResponseHandler.setLdapServer( this );
1378        this.handler.addSentMessageHandler( ModifyResponse.class, this.modifyResponseHandler );
1379    }
1380
1381
1382    /**
1383     * @return The MessageSent handler for the ModifyDnRequest
1384     */
1385    public LdapRequestHandler<ModifyDnRequest> getModifyDnRequestHandler()
1386    {
1387        return modifyDnRequestHandler;
1388    }
1389
1390
1391    /**
1392     * @return The MessageSent handler for the ModifyDnResponse
1393     */
1394    public LdapResponseHandler<ModifyDnResponse> getModifyDnResponseHandler()
1395    {
1396        return modifyDnResponseHandler;
1397    }
1398
1399
1400    /**
1401     * Inject the MessageReceived and MessageSent handler into the IoHandler
1402     *
1403     * @param modifyDnRequestHandler The ModifyDnRequest message received handler
1404     * @param modifyDnResponseHandler The ModifyDnResponse message sent handler
1405     */
1406    public void setModifyDnHandlers( LdapRequestHandler<ModifyDnRequest> modifyDnRequestHandler,
1407        LdapResponseHandler<ModifyDnResponse> modifyDnResponseHandler )
1408    {
1409        handler.removeReceivedMessageHandler( ModifyDnRequest.class );
1410        this.modifyDnRequestHandler = modifyDnRequestHandler;
1411        this.modifyDnRequestHandler.setLdapServer( this );
1412        this.handler.addReceivedMessageHandler( ModifyDnRequest.class, this.modifyDnRequestHandler );
1413
1414        handler.removeSentMessageHandler( ModifyDnResponse.class );
1415        this.modifyDnResponseHandler = modifyDnResponseHandler;
1416        this.modifyDnResponseHandler.setLdapServer( this );
1417        this.handler.addSentMessageHandler( ModifyDnResponse.class, this.modifyDnResponseHandler );
1418    }
1419
1420
1421    /**
1422     * @return The MessageReceived handler for the SearchRequest
1423     */
1424    public LdapRequestHandler<SearchRequest> getSearchRequestHandler()
1425    {
1426        return searchRequestHandler;
1427    }
1428
1429
1430    /**
1431     * @return The MessageSent handler for the SearchResultEntry
1432     */
1433    public LdapResponseHandler<SearchResultEntry> getSearchResultEntryHandler()
1434    {
1435        return searchResultEntryHandler;
1436    }
1437
1438
1439    /**
1440     * @return The MessageSent handler for the SearchResultReference
1441     */
1442    public LdapResponseHandler<SearchResultReference> getSearchResultReferenceHandler()
1443    {
1444        return searchResultReferenceHandler;
1445    }
1446
1447
1448    /**
1449     * @return The MessageSent handler for the SearchResultDone
1450     */
1451    public LdapResponseHandler<SearchResultDone> getSearchResultDoneHandler()
1452    {
1453        return searchResultDoneHandler;
1454    }
1455
1456
1457    /**
1458     * Inject the MessageReceived and MessageSent handler into the IoHandler
1459     *
1460     * @param searchRequestHandler The SearchRequest message received handler
1461     * @param searchResultEntryHandler The SearchResultEntry message sent handler
1462     * @param searchResultReferenceHandler The SearchResultReference message sent handler
1463     * @param searchResultDoneHandler The SearchResultDone message sent handler
1464     */
1465    public void setSearchHandlers( LdapRequestHandler<SearchRequest> searchRequestHandler,
1466        LdapResponseHandler<SearchResultEntry> searchResultEntryHandler,
1467        LdapResponseHandler<SearchResultReference> searchResultReferenceHandler,
1468        LdapResponseHandler<SearchResultDone> searchResultDoneHandler
1469        )
1470    {
1471        this.handler.removeReceivedMessageHandler( SearchRequest.class );
1472        this.searchRequestHandler = searchRequestHandler;
1473        this.searchRequestHandler.setLdapServer( this );
1474        this.handler.addReceivedMessageHandler( SearchRequest.class, this.searchRequestHandler );
1475
1476        this.handler.removeSentMessageHandler( SearchResultEntry.class );
1477        this.searchResultEntryHandler = searchResultEntryHandler;
1478        this.searchResultEntryHandler.setLdapServer( this );
1479        this.handler.addSentMessageHandler( SearchResultEntry.class, this.searchResultEntryHandler );
1480
1481        this.handler.removeSentMessageHandler( SearchResultReference.class );
1482        this.searchResultReferenceHandler = searchResultReferenceHandler;
1483        this.searchResultReferenceHandler.setLdapServer( this );
1484        this.handler.addSentMessageHandler( SearchResultReference.class, this.searchResultReferenceHandler );
1485
1486        this.handler.removeSentMessageHandler( SearchResultDone.class );
1487        this.searchResultDoneHandler = searchResultDoneHandler;
1488        this.searchResultDoneHandler.setLdapServer( this );
1489        this.handler.addSentMessageHandler( SearchResultDone.class, this.searchResultDoneHandler );
1490    }
1491
1492
1493    /**
1494     * @return The MessageReceived handler for the UnbindRequest
1495     */
1496    public LdapRequestHandler<UnbindRequest> getUnbindRequestHandler()
1497    {
1498        return unbindRequestHandler;
1499    }
1500
1501
1502    /**
1503     * Inject the MessageReceived handler into the IoHandler
1504     *
1505     * @param unbindRequestHandler The UnbindRequest message received handler
1506     */
1507    public void setUnbindHandler( LdapRequestHandler<UnbindRequest> unbindRequestHandler )
1508    {
1509        this.handler.removeReceivedMessageHandler( UnbindRequest.class );
1510        this.unbindRequestHandler = unbindRequestHandler;
1511        this.unbindRequestHandler.setLdapServer( this );
1512        this.handler.addReceivedMessageHandler( UnbindRequest.class, this.unbindRequestHandler );
1513    }
1514
1515
1516    /**
1517     * @return The underlying TCP transport port, or -1 if no transport has been
1518     * initialized
1519     */
1520    public int getPort()
1521    {
1522        if ( transports == null )
1523        {
1524            return -1;
1525        }
1526
1527        for ( Transport transport : transports )
1528        {
1529            if ( transport instanceof UdpTransport )
1530            {
1531                continue;
1532            }
1533
1534            if ( !transport.isSSLEnabled() )
1535            {
1536                return transport.getPort();
1537            }
1538        }
1539
1540        return -1;
1541    }
1542
1543
1544    /**
1545     * @return The underlying SSL enabled TCP transport port, or -1 if no transport has been
1546     * initialized
1547     */
1548    public int getPortSSL()
1549    {
1550        if ( transports == null )
1551        {
1552            return -1;
1553        }
1554
1555        for ( Transport transport : transports )
1556        {
1557            if ( transport instanceof UdpTransport )
1558            {
1559                continue;
1560            }
1561
1562            if ( transport.isSSLEnabled() )
1563            {
1564                return transport.getPort();
1565            }
1566        }
1567
1568        return -1;
1569    }
1570
1571
1572    @Override
1573    public boolean isStarted()
1574    {
1575        return started;
1576    }
1577
1578
1579    /**
1580     */
1581    @Override
1582    public void setStarted( boolean started )
1583    {
1584        this.started = started;
1585    }
1586
1587
1588    /**
1589     * @return The keystore path
1590     */
1591    public String getKeystoreFile()
1592    {
1593        return keystoreFile;
1594    }
1595
1596
1597    /**
1598     * Set the external keystore path
1599     * @param keystoreFile The external keystore path
1600     */
1601    public void setKeystoreFile( String keystoreFile )
1602    {
1603        this.keystoreFile = keystoreFile;
1604    }
1605
1606
1607    /**
1608     * @return The certificate password
1609     */
1610    public String getCertificatePassword()
1611    {
1612        return certificatePassword;
1613    }
1614
1615
1616    /**
1617     * Set the certificate password.
1618     * @param certificatePassword the certificate password
1619     */
1620    public void setCertificatePassword( String certificatePassword )
1621    {
1622        this.certificatePassword = certificatePassword;
1623    }
1624
1625
1626    public void setReplicationReqHandler( ReplicationRequestHandler replicationProvider )
1627    {
1628        this.replicationReqHandler = replicationProvider;
1629    }
1630
1631
1632    public ReplicationRequestHandler getReplicationReqHandler()
1633    {
1634        return replicationReqHandler;
1635    }
1636
1637
1638    public void setReplConsumers( List<ReplicationConsumer> replConsumers )
1639    {
1640        this.replConsumers = replConsumers;
1641    }
1642
1643
1644    /**
1645     * @return the key manager factory of the server keystore
1646     */
1647    public KeyManagerFactory getKeyManagerFactory()
1648    {
1649        return keyManagerFactory;
1650    }
1651
1652
1653    /**
1654     * @return The maximum allowed size for an incoming PDU
1655     */
1656    public int getMaxPDUSize()
1657    {
1658        return maxPDUSize;
1659    }
1660
1661
1662    /**
1663     * Set the maximum allowed size for an incoming PDU
1664     * @param maxPDUSize A positive number of bytes for the PDU. A negative or
1665     * null value will be transformed to {@link Integer#MAX_VALUE}
1666     */
1667    public void setMaxPDUSize( int maxPDUSize )
1668    {
1669        if ( maxPDUSize <= 0 )
1670        {
1671            maxPDUSize = Integer.MAX_VALUE;
1672        }
1673
1674        this.maxPDUSize = maxPDUSize;
1675    }
1676
1677
1678    /**
1679     * @return the number of seconds pinger thread sleeps between subsequent pings
1680     */
1681    public int getReplPingerSleepTime()
1682    {
1683        return pingerSleepTime;
1684    }
1685
1686
1687    /**
1688     * The number of seconds pinger thread should sleep before pinging the providers
1689     *
1690     * @param pingerSleepTime The delay between 2 pings
1691     */
1692    public void setReplPingerSleepTime( int pingerSleepTime )
1693    {
1694        this.pingerSleepTime = pingerSleepTime;
1695    }
1696
1697
1698    /**
1699     * Gives the list of enabled cipher suites
1700     * <br>
1701     * This method has been deprecated, please set this list in the TcpTransport class
1702     * <br>
1703     *
1704     * @return The list of ciphers that can be used
1705     * @deprecated Set this list in the {@link TcpTransport} class
1706     */
1707    @Deprecated
1708    public List<String> getEnabledCipherSuites()
1709    {
1710        return enabledCipherSuites;
1711    }
1712
1713
1714    /**
1715     * Sets the list of cipher suites to be used in LDAPS and StartTLS
1716     * <br>
1717     * This method has been deprecated, please set this list in the TcpTransport class
1718     * <br>
1719     *
1720     * @param enabledCipherSuites if null the default cipher suites will be used
1721     * @deprecated Get this list from the {@link TcpTransport} class
1722     */
1723    @Deprecated
1724    public void setEnabledCipherSuites( List<String> enabledCipherSuites )
1725    {
1726        this.enabledCipherSuites = enabledCipherSuites;
1727    }
1728
1729
1730    /**
1731     * @see Object#toString()
1732     */
1733    @Override
1734    public String toString()
1735    {
1736        StringBuilder sb = new StringBuilder();
1737
1738        sb.append( "LdapServer[" ).append( getServiceName() ).append( "], listening on :" ).append( '\n' );
1739
1740        if ( getTransports() != null )
1741        {
1742            for ( Transport transport : getTransports() )
1743            {
1744                sb.append( "    " ).append( transport ).append( '\n' );
1745            }
1746        }
1747
1748        return sb.toString();
1749    }
1750}