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