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