001    /*
002     * Copyright 2010-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2010-2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.listener;
022    
023    
024    
025    import java.net.InetAddress;
026    import javax.net.ServerSocketFactory;
027    
028    import com.unboundid.util.Mutable;
029    import com.unboundid.util.ThreadSafety;
030    import com.unboundid.util.ThreadSafetyLevel;
031    import com.unboundid.util.Validator;
032    
033    
034    
035    /**
036     * This class provides a mechanism for defining the configuration to use for an
037     * {@link LDAPListener} instance.  Note that while instances of this class are
038     * not inherently threadsafe, a private copy of the configuration will be
039     * created whenever a new {@code LDAPListener} is created so that this
040     * configuration may continue to be altered for new instances without impacting
041     * any existing listeners.
042     */
043    @Mutable()
044    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
045    public final class LDAPListenerConfig
046    {
047      // Indicates whether to use the SO_KEEPALIVE socket option for sockets
048      // accepted by the listener.
049      private boolean useKeepAlive;
050    
051      // Indicates whether to use the SO_LINGER socket option for sockets accepted
052      // by the listener.
053      private boolean useLinger;
054    
055      // Indicates whether to use the SO_REUSEADDR socket option for sockets
056      // accepted by the listener.
057      private boolean useReuseAddress;
058    
059      // Indicates whether to use the TCP_NODELAY for sockets accepted by the
060      // listener.
061      private boolean useTCPNoDelay;
062    
063      // The address on which to listen for client connections.
064      private InetAddress listenAddress;
065    
066      // The linger timeout in seconds to use for sockets accepted by the listener.
067      private int lingerTimeout;
068    
069      // The port on which to listen for client connections.
070      private int listenPort;
071    
072      // The maximum number of concurrent connections that will be allowed.
073      private int maxConnections;
074    
075      // The receive buffer size to use for sockets accepted by the listener.
076      private int receiveBufferSize;
077    
078      // The send buffer size to use for sockets accepted by the listener.
079      private int sendBufferSize;
080    
081      // The exception handler to use for the listener and associated connections.
082      private LDAPListenerExceptionHandler exceptionHandler;
083    
084      // The request handler that will be used to process requests read from
085      // clients.
086      private LDAPListenerRequestHandler requestHandler;
087    
088      // The factory that will be used to create server sockets.
089      private ServerSocketFactory serverSocketFactory;
090    
091    
092    
093      /**
094       * Creates a new listener configuration.
095       *
096       * @param  listenPort      The port on which to listen for client connections.
097       *                         It must be an integer between 1 and 65535, or 0 to
098       *                         indicate that a free port should be chosen by the
099       *                         JVM.
100       * @param  requestHandler  The request handler that will be used to process
101       *                         requests read from clients.  It must not be
102       *                         {@code null}.
103       */
104      public LDAPListenerConfig(final int listenPort,
105                                final LDAPListenerRequestHandler requestHandler)
106      {
107        Validator.ensureTrue((listenPort >= 0) && (listenPort <= 65535));
108        Validator.ensureNotNull(requestHandler);
109    
110        this.listenPort     = listenPort;
111        this.requestHandler = requestHandler;
112    
113        useKeepAlive        = true;
114        useLinger           = true;
115        useReuseAddress     = true;
116        useTCPNoDelay       = true;
117        lingerTimeout       = 5;
118        listenAddress       = null;
119        maxConnections      = 0;
120        receiveBufferSize   = 0;
121        sendBufferSize      = 0;
122        exceptionHandler    = null;
123        serverSocketFactory = ServerSocketFactory.getDefault();
124      }
125    
126    
127    
128      /**
129       * Retrieves the port number on which to listen for client connections.  A
130       * value of zero indicates that the listener should allow the JVM to choose a
131       * free port.
132       *
133       * @return  The port number on which to listen for client connections.
134       */
135      public int getListenPort()
136      {
137        return listenPort;
138      }
139    
140    
141    
142      /**
143       * Specifies the port number on which to listen for client connections.  The
144       * provided value must be between 1 and 65535, or it may be 0 to indicate that
145       * the JVM should select a free port on the system.
146       *
147       * @param  listenPort  The port number on which to listen for client
148       *                     connections.
149       */
150      public void setListenPort(final int listenPort)
151      {
152        Validator.ensureTrue((listenPort >= 0) && (listenPort <= 65535));
153    
154        this.listenPort = listenPort;
155      }
156    
157    
158    
159      /**
160       * Retrieves the LDAP listener request handler that should be used to process
161       * requests read from clients.
162       *
163       * @return  The LDAP listener request handler that should be used to process
164       *          requests read from clients.
165       */
166      public LDAPListenerRequestHandler getRequestHandler()
167      {
168        return requestHandler;
169      }
170    
171    
172    
173      /**
174       * Specifies the LDAP listener request handler that should be used to process
175       * requests read from clients.
176       *
177       * @param  requestHandler  The LDAP listener request handler that should be
178       *                         used to process requests read from clients.  It
179       *                         must not be {@code null}.
180       */
181      public void setRequestHandler(final LDAPListenerRequestHandler requestHandler)
182      {
183        Validator.ensureNotNull(requestHandler);
184    
185        this.requestHandler = requestHandler;
186      }
187    
188    
189    
190      /**
191       * Indicates whether to use the SO_KEEPALIVE socket option for sockets
192       * accepted by the listener.
193       *
194       * @return  {@code true} if the SO_KEEPALIVE socket option should be used for
195       *          sockets accepted by the listener, or {@code false} if not.
196       */
197      public boolean useKeepAlive()
198      {
199        return useKeepAlive;
200      }
201    
202    
203    
204      /**
205       * Specifies whether to use the SO_KEEPALIVE socket option for sockets
206       * accepted by the listener.
207       *
208       * @param  useKeepAlive  Indicates whether to use the SO_KEEPALIVE socket
209       *                       option for sockets accepted by the listener.
210       */
211      public void setUseKeepAlive(final boolean useKeepAlive)
212      {
213        this.useKeepAlive = useKeepAlive;
214      }
215    
216    
217    
218      /**
219       * Indicates whether to use the SO_LINGER socket option for sockets accepted
220       * by the listener.
221       *
222       * @return  {@code true} if the SO_LINGER socket option should be used for
223       *          sockets accepted by the listener, or {@code false} if not.
224       */
225      public boolean useLinger()
226      {
227        return useLinger;
228      }
229    
230    
231    
232      /**
233       * Specifies whether to use the SO_LINGER socket option for sockets accepted
234       * by the listener.
235       *
236       * @param  useLinger  Indicates whether to use the SO_LINGER socket option for
237       *                    sockets accepted by the listener.
238       */
239      public void setUseLinger(final boolean useLinger)
240      {
241        this.useLinger = useLinger;
242      }
243    
244    
245    
246      /**
247       * Indicates whether to use the SO_REUSEADDR socket option for sockets
248       * accepted by the listener.
249       *
250       * @return  {@code true} if the SO_REUSEADDR socket option should be used for
251       *          sockets accepted by the listener, or {@code false} if not.
252       */
253      public boolean useReuseAddress()
254      {
255        return useReuseAddress;
256      }
257    
258    
259    
260      /**
261       * Specifies whether to use the SO_REUSEADDR socket option for sockets
262       * accepted by the listener.
263       *
264       * @param  useReuseAddress  Indicates whether to use the SO_REUSEADDR socket
265       *                          option for sockets accepted by the listener.
266       */
267      public void setUseReuseAddress(final boolean useReuseAddress)
268      {
269        this.useReuseAddress = useReuseAddress;
270      }
271    
272    
273    
274      /**
275       * Indicates whether to use the TCP_NODELAY socket option for sockets accepted
276       * by the listener.
277       *
278       * @return  {@code true} if the TCP_NODELAY socket option should be used for
279       *          sockets accepted by the listener, or {@code false} if not.
280       */
281      public boolean useTCPNoDelay()
282      {
283        return useTCPNoDelay;
284      }
285    
286    
287    
288      /**
289       * Specifies whether to use the TCP_NODELAY socket option for sockets accepted
290       * by the listener.
291       *
292       * @param  useTCPNoDelay  Indicates whether to use the TCP_NODELAY socket
293       *                        option for sockets accepted by the listener.
294       */
295      public void setUseTCPNoDelay(final boolean useTCPNoDelay)
296      {
297        this.useTCPNoDelay = useTCPNoDelay;
298      }
299    
300    
301    
302      /**
303       * Retrieves the address on which to listen for client connections, if
304       * defined.
305       *
306       * @return  The address on which to listen for client connections, or
307       *          {@code null} if it should listen on all available addresses on all
308       *          interfaces.
309       */
310      public InetAddress getListenAddress()
311      {
312        return listenAddress;
313      }
314    
315    
316    
317      /**
318       * Specifies the address on which to listen for client connections.
319       *
320       * @param  listenAddress  The address on which to listen for client
321       *                        connections.  It may be {@code null} to indicate
322       *                        that it should listen on all available addresses on
323       *                        all interfaces.
324       */
325      public void setListenAddress(final InetAddress listenAddress)
326      {
327        this.listenAddress = listenAddress;
328      }
329    
330    
331    
332      /**
333       * Retrieves the timeout in seconds that should be used if the SO_LINGER
334       * socket option is enabled.
335       *
336       * @return  The timeout in seconds that should be used if the SO_LINGER socket
337       *           option is enabled.
338       */
339      public int getLingerTimeoutSeconds()
340      {
341        return lingerTimeout;
342      }
343    
344    
345    
346      /**
347       * Specifies the timeout in seconds that should be used if the SO_LINGER
348       * socket option is enabled.
349       *
350       * @param  lingerTimeout  The timeout in seconds that should be used if the
351       *                        SO_LINGER socket option is enabled.  The value must
352       *                        be between 0 and 65535, inclusive.
353       */
354      public void setLingerTimeoutSeconds(final int lingerTimeout)
355      {
356        Validator.ensureTrue((lingerTimeout >= 0) && (lingerTimeout <= 65535));
357    
358        this.lingerTimeout = lingerTimeout;
359      }
360    
361    
362    
363      /**
364       * Retrieves the maximum number of concurrent connections that the listener
365       * will allow.  If a client tries to establish a new connection while the
366       * listener already has the maximum number of concurrent connections, then the
367       * new connection will be rejected.
368       *
369       * @return  The maximum number of concurrent connections that the listener
370       *          will allow, or zero if no limit should be enforced.
371       */
372      public int getMaxConnections()
373      {
374        return maxConnections;
375      }
376    
377    
378    
379      /**
380       * Specifies the maximum number of concurrent connections that the listener
381       * will allow.  If a client tries to establish a new connection while the
382       * listener already has the maximum number of concurrent connections, then the
383       * new connection will be rejected.
384       *
385       * @param  maxConnections  The maximum number of concurrent connections that
386       *                         the listener will allow.  A value that is less than
387       *                         or equal to zero indicates no limit.
388       */
389      public void setMaxConnections(final int maxConnections)
390      {
391        if (maxConnections > 0)
392        {
393          this.maxConnections = maxConnections;
394        }
395        else
396        {
397          this.maxConnections = 0;
398        }
399      }
400    
401    
402    
403      /**
404       * Retrieves the receive buffer size that should be used for sockets accepted
405       * by the listener.
406       *
407       * @return  The receive buffer size that should be used for sockets accepted
408       *          by the listener, or 0 if the default receive buffer size should be
409       *          used.
410       */
411      public int getReceiveBufferSize()
412      {
413        return receiveBufferSize;
414      }
415    
416    
417    
418      /**
419       * Specifies the receive buffer size that should be used for sockets accepted
420       * by the listener.  A value less than or equal to zero indicates that the
421       * default receive buffer size should be used.
422       *
423       * @param  receiveBufferSize  The receive buffer size that should be used for
424       *                            sockets accepted by the listener.
425       */
426      public void setReceiveBufferSize(final int receiveBufferSize)
427      {
428        if (receiveBufferSize > 0)
429        {
430          this.receiveBufferSize = receiveBufferSize;
431        }
432        else
433        {
434          this.receiveBufferSize = 0;
435        }
436      }
437    
438    
439    
440      /**
441       * Retrieves the send  buffer size that should be used for sockets accepted
442       * by the listener.
443       *
444       * @return  The send buffer size that should be used for sockets accepted by
445       *          the listener, or 0 if the default send buffer size should be used.
446       */
447      public int getSendBufferSize()
448      {
449        return sendBufferSize;
450      }
451    
452    
453    
454      /**
455       * Specifies the send buffer size that should be used for sockets accepted by
456       * the listener.  A value less than or equal to zero indicates that the
457       * default send buffer size should be used.
458       *
459       * @param  sendBufferSize  The send buffer size that should be used for
460       *                         sockets accepted by the listener.
461       */
462      public void setSendBufferSize(final int sendBufferSize)
463      {
464        if (sendBufferSize > 0)
465        {
466          this.sendBufferSize = sendBufferSize;
467        }
468        else
469        {
470          this.sendBufferSize = 0;
471        }
472      }
473    
474    
475    
476      /**
477       * Retrieves the exception handler that should be notified of any exceptions
478       * caught while attempting to accept or interact with a client connection.
479       *
480       * @return  The exception handler that should be notified of any exceptions
481       *          caught while attempting to accept or interact with a client
482       *          connection, or {@code null} if none is defined.
483       */
484      public LDAPListenerExceptionHandler getExceptionHandler()
485      {
486        return exceptionHandler;
487      }
488    
489    
490    
491      /**
492       * Specifies the exception handler that should be notified of any exceptions
493       * caught while attempting to accept or interact with a client connection.
494       *
495       * @param  exceptionHandler  The exception handler that should be notified of
496       *                           any exceptions encountered during processing.  It
497       *                           may be {@code null} if no exception handler
498       *                           should be used.
499       */
500      public void setExceptionHandler(
501                       final LDAPListenerExceptionHandler exceptionHandler)
502      {
503        this.exceptionHandler = exceptionHandler;
504      }
505    
506    
507    
508      /**
509       * Retrieves the factory that will be used to create the server socket that
510       * will listen for client connections.
511       *
512       * @return  The factory that will be used to create the server socket that
513       *          will listen for client connections.
514       */
515      public ServerSocketFactory getServerSocketFactory()
516      {
517        return serverSocketFactory;
518      }
519    
520    
521    
522      /**
523       * Specifies the factory that will be used to create the server socket that
524       * will listen for client connections.
525       *
526       * @param  serverSocketFactory  The factory that will be used to create the
527       *                              server socket that will listen for client
528       *                              connections.  It may be {@code null} to use
529       *                              the JVM-default server socket factory.
530       */
531      public void setServerSocketFactory(
532                       final ServerSocketFactory serverSocketFactory)
533      {
534        if (serverSocketFactory == null)
535        {
536          this.serverSocketFactory = ServerSocketFactory.getDefault();
537        }
538        else
539        {
540          this.serverSocketFactory = serverSocketFactory;
541        }
542      }
543    
544    
545    
546    /**
547       * Creates a copy of this configuration that may be altered without impacting
548       * this configuration, and which will not be altered by changes to this
549       * configuration.
550       *
551       * @return  A copy of this configuration that may be altered without impacting
552       *          this configuration, and which will not be altered by changes to
553       *          this configuration.
554       */
555      public LDAPListenerConfig duplicate()
556      {
557        final LDAPListenerConfig copy =
558             new LDAPListenerConfig(listenPort, requestHandler);
559    
560        copy.useKeepAlive        = useKeepAlive;
561        copy.useLinger           = useLinger;
562        copy.useReuseAddress     = useReuseAddress;
563        copy.useTCPNoDelay       = useTCPNoDelay;
564        copy.listenAddress       = listenAddress;
565        copy.lingerTimeout       = lingerTimeout;
566        copy.maxConnections      = maxConnections;
567        copy.receiveBufferSize   = receiveBufferSize;
568        copy.sendBufferSize      = sendBufferSize;
569        copy.exceptionHandler    = exceptionHandler;
570        copy.serverSocketFactory = serverSocketFactory;
571    
572        return copy;
573      }
574    
575    
576    
577      /**
578       * Retrieves a string representation of this LDAP listener config.
579       *
580       * @return  A string representation of this LDAP listener config.
581       */
582      @Override()
583      public String toString()
584      {
585        final StringBuilder buffer = new StringBuilder();
586        toString(buffer);
587        return buffer.toString();
588      }
589    
590    
591    
592      /**
593       * Appends a string representation of this LDAP listener config to the
594       * provided buffer.
595       *
596       * @param  buffer  The buffer to which the information should be appended.
597       */
598      public void toString(final StringBuilder buffer)
599      {
600        buffer.append("LDAPListenerConfig(listenAddress=");
601    
602        if (listenAddress == null)
603        {
604          buffer.append("null");
605        }
606        else
607        {
608          buffer.append('\'');
609          buffer.append(listenAddress.getHostAddress());
610          buffer.append('\'');
611        }
612    
613        buffer.append(", listenPort=");
614        buffer.append(listenPort);
615        buffer.append(", requestHandlerClass='");
616        buffer.append(requestHandler.getClass().getName());
617        buffer.append("', serverSocketFactoryClass='");
618        buffer.append(serverSocketFactory.getClass().getName());
619        buffer.append('\'');
620    
621        if (exceptionHandler != null)
622        {
623          buffer.append(", exceptionHandlerClass='");
624          buffer.append(exceptionHandler.getClass().getName());
625          buffer.append('\'');
626        }
627    
628        buffer.append(", useKeepAlive=");
629        buffer.append(useKeepAlive);
630        buffer.append(", useTCPNoDelay=");
631        buffer.append(useTCPNoDelay);
632    
633        if (useLinger)
634        {
635          buffer.append(", useLinger=true, lingerTimeout=");
636          buffer.append(lingerTimeout);
637        }
638        else
639        {
640          buffer.append(", useLinger=false");
641        }
642    
643        buffer.append(", maxConnections=");
644        buffer.append(maxConnections);
645        buffer.append(", useReuseAddress=");
646        buffer.append(useReuseAddress);
647        buffer.append(", receiveBufferSize=");
648        buffer.append(receiveBufferSize);
649        buffer.append(", sendBufferSize=");
650        buffer.append(sendBufferSize);
651        buffer.append(')');
652      }
653    }