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}