001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2009-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017 018package org.forgerock.opendj.ldap; 019 020import static org.forgerock.opendj.ldap.RequestHandlerFactoryAdapter.adaptRequestHandler; 021import static org.forgerock.util.time.Duration.duration; 022 023import java.net.InetAddress; 024import java.net.InetSocketAddress; 025import java.util.Collection; 026import java.util.concurrent.ScheduledExecutorService; 027import java.util.concurrent.ThreadLocalRandom; 028import java.util.concurrent.TimeUnit; 029import java.util.concurrent.atomic.AtomicInteger; 030 031import org.forgerock.opendj.ldap.requests.AddRequest; 032import org.forgerock.opendj.ldap.requests.CRAMMD5SASLBindRequest; 033import org.forgerock.opendj.ldap.requests.CompareRequest; 034import org.forgerock.opendj.ldap.requests.DeleteRequest; 035import org.forgerock.opendj.ldap.requests.DigestMD5SASLBindRequest; 036import org.forgerock.opendj.ldap.requests.GSSAPISASLBindRequest; 037import org.forgerock.opendj.ldap.requests.ModifyDNRequest; 038import org.forgerock.opendj.ldap.requests.ModifyRequest; 039import org.forgerock.opendj.ldap.requests.PasswordModifyExtendedRequest; 040import org.forgerock.opendj.ldap.requests.PlainSASLBindRequest; 041import org.forgerock.opendj.ldap.requests.Request; 042import org.forgerock.opendj.ldap.requests.SearchRequest; 043import org.forgerock.opendj.ldap.requests.SimpleBindRequest; 044import org.forgerock.util.Function; 045import org.forgerock.util.Option; 046import org.forgerock.util.Options; 047import org.forgerock.util.Reject; 048import org.forgerock.util.promise.NeverThrowsException; 049import org.forgerock.util.promise.Promise; 050import org.forgerock.util.time.Duration; 051 052/** 053 * This class contains methods for creating and manipulating connection 054 * factories and connections. 055 */ 056public final class Connections { 057 /** 058 * Specifies the interval between successive attempts to reconnect to offline load-balanced connection factories. 059 * The default configuration is to attempt to reconnect every second. 060 */ 061 public static final Option<Duration> LOAD_BALANCER_MONITORING_INTERVAL = Option.withDefault(duration("1 seconds")); 062 063 /** 064 * Specifies the event listener which should be notified whenever a load-balanced connection factory changes state 065 * from online to offline or vice-versa. By default events will be logged to the {@code LoadBalancingAlgorithm} 066 * logger using the {@link LoadBalancerEventListener#LOG_EVENTS} listener. 067 */ 068 public static final Option<LoadBalancerEventListener> LOAD_BALANCER_EVENT_LISTENER = 069 Option.of(LoadBalancerEventListener.class, LoadBalancerEventListener.LOG_EVENTS); 070 071 /** 072 * Specifies the scheduler which will be used for periodically reconnecting to offline connection factories. A 073 * system-wide scheduler will be used by default. 074 */ 075 public static final Option<ScheduledExecutorService> LOAD_BALANCER_SCHEDULER = 076 Option.of(ScheduledExecutorService.class, null); 077 078 /** 079 * Creates a new connection pool which creates new connections as needed 080 * using the provided connection factory, but will reuse previously 081 * allocated connections when they are available. 082 * <p> 083 * Connections which have not been used for sixty seconds are closed and 084 * removed from the pool. Thus, a pool that remains idle for long enough 085 * will not contain any cached connections. 086 * <p> 087 * Connections obtained from the connection pool are guaranteed to be valid 088 * immediately before being returned to the calling application. More 089 * specifically, connections which have remained idle in the connection pool 090 * for a long time and which have been remotely closed due to a time out 091 * will never be returned. However, once a pooled connection has been 092 * obtained it is the responsibility of the calling application to handle 093 * subsequent connection failures, these being signaled via a 094 * {@link ConnectionException}. 095 * 096 * @param factory 097 * The connection factory to use for creating new connections. 098 * @return The new connection pool. 099 * @throws NullPointerException 100 * If {@code factory} was {@code null}. 101 */ 102 public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory) { 103 return new CachedConnectionPool(factory, 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, null); 104 } 105 106 /** 107 * Creates a new connection pool which creates new connections as needed 108 * using the provided connection factory, but will reuse previously 109 * allocated connections when they are available. 110 * <p> 111 * Attempts to use more than {@code maximumPoolSize} connections at once 112 * will block until a connection is released back to the pool. In other 113 * words, this pool will prevent applications from using more than 114 * {@code maximumPoolSize} connections at the same time. 115 * <p> 116 * Connections which have not been used for the provided {@code idleTimeout} 117 * period are closed and removed from the pool, until there are only 118 * {@code corePoolSize} connections remaining. 119 * <p> 120 * Connections obtained from the connection pool are guaranteed to be valid 121 * immediately before being returned to the calling application. More 122 * specifically, connections which have remained idle in the connection pool 123 * for a long time and which have been remotely closed due to a time out 124 * will never be returned. However, once a pooled connection has been 125 * obtained it is the responsibility of the calling application to handle 126 * subsequent connection failures, these being signaled via a 127 * {@link ConnectionException}. 128 * 129 * @param factory 130 * The connection factory to use for creating new connections. 131 * @param corePoolSize 132 * The minimum number of connections to keep in the pool, even if 133 * they are idle. 134 * @param maximumPoolSize 135 * The maximum number of connections to allow in the pool. 136 * @param idleTimeout 137 * The time out period, after which unused non-core connections 138 * will be closed. 139 * @param unit 140 * The time unit for the {@code keepAliveTime} argument. 141 * @return The new connection pool. 142 * @throws IllegalArgumentException 143 * If {@code corePoolSize}, {@code maximumPoolSize} are less 144 * than or equal to zero, or if {@code idleTimeout} is negative, 145 * or if {@code corePoolSize} is greater than 146 * {@code maximumPoolSize}, or if {@code idleTimeout} is 147 * non-zero and {@code unit} is {@code null}. 148 * @throws NullPointerException 149 * If {@code factory} was {@code null}. 150 */ 151 public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory, 152 final int corePoolSize, final int maximumPoolSize, final long idleTimeout, 153 final TimeUnit unit) { 154 return new CachedConnectionPool(factory, corePoolSize, maximumPoolSize, idleTimeout, unit, 155 null); 156 } 157 158 /** 159 * Creates a new connection pool which creates new connections as needed 160 * using the provided connection factory, but will reuse previously 161 * allocated connections when they are available. 162 * <p> 163 * Attempts to use more than {@code maximumPoolSize} connections at once 164 * will block until a connection is released back to the pool. In other 165 * words, this pool will prevent applications from using more than 166 * {@code maximumPoolSize} connections at the same time. 167 * <p> 168 * Connections which have not been used for the provided {@code idleTimeout} 169 * period are closed and removed from the pool, until there are only 170 * {@code corePoolSize} connections remaining. 171 * <p> 172 * Connections obtained from the connection pool are guaranteed to be valid 173 * immediately before being returned to the calling application. More 174 * specifically, connections which have remained idle in the connection pool 175 * for a long time and which have been remotely closed due to a time out 176 * will never be returned. However, once a pooled connection has been 177 * obtained it is the responsibility of the calling application to handle 178 * subsequent connection failures, these being signaled via a 179 * {@link ConnectionException}. 180 * 181 * @param factory 182 * The connection factory to use for creating new connections. 183 * @param corePoolSize 184 * The minimum number of connections to keep in the pool, even if 185 * they are idle. 186 * @param maximumPoolSize 187 * The maximum number of connections to allow in the pool. 188 * @param idleTimeout 189 * The time out period, after which unused non-core connections 190 * will be closed. 191 * @param unit 192 * The time unit for the {@code keepAliveTime} argument. 193 * @param scheduler 194 * The scheduler which should be used for periodically checking 195 * for idle connections, or {@code null} if the default scheduler 196 * should be used. 197 * @return The new connection pool. 198 * @throws IllegalArgumentException 199 * If {@code corePoolSize}, {@code maximumPoolSize} are less 200 * than or equal to zero, or if {@code idleTimeout} is negative, 201 * or if {@code corePoolSize} is greater than 202 * {@code maximumPoolSize}, or if {@code idleTimeout} is 203 * non-zero and {@code unit} is {@code null}. 204 * @throws NullPointerException 205 * If {@code factory} was {@code null}. 206 */ 207 public static ConnectionPool newCachedConnectionPool(final ConnectionFactory factory, 208 final int corePoolSize, final int maximumPoolSize, final long idleTimeout, 209 final TimeUnit unit, final ScheduledExecutorService scheduler) { 210 return new CachedConnectionPool(factory, corePoolSize, maximumPoolSize, idleTimeout, unit, 211 scheduler); 212 } 213 214 /** 215 * Creates a new connection pool which will maintain {@code poolSize} 216 * connections created using the provided connection factory. 217 * <p> 218 * Attempts to use more than {@code poolSize} connections at once will block 219 * until a connection is released back to the pool. In other words, this 220 * pool will prevent applications from using more than {@code poolSize} 221 * connections at the same time. 222 * <p> 223 * Connections obtained from the connection pool are guaranteed to be valid 224 * immediately before being returned to the calling application. More 225 * specifically, connections which have remained idle in the connection pool 226 * for a long time and which have been remotely closed due to a time out 227 * will never be returned. However, once a pooled connection has been 228 * obtained it is the responsibility of the calling application to handle 229 * subsequent connection failures, these being signaled via a 230 * {@link ConnectionException}. 231 * 232 * @param factory 233 * The connection factory to use for creating new connections. 234 * @param poolSize 235 * The maximum size of the connection pool. 236 * @return The new connection pool. 237 * @throws IllegalArgumentException 238 * If {@code poolSize} is negative. 239 * @throws NullPointerException 240 * If {@code factory} was {@code null}. 241 */ 242 public static ConnectionPool newFixedConnectionPool(final ConnectionFactory factory, 243 final int poolSize) { 244 return new CachedConnectionPool(factory, poolSize, poolSize, 0L, null, null); 245 } 246 247 /** 248 * Creates a new internal client connection which will route requests to the 249 * provided {@code RequestHandler}. 250 * <p> 251 * When processing requests, {@code RequestHandler} implementations are 252 * passed a {@code RequestContext} having a pseudo {@code requestID} which 253 * is incremented for each successive internal request on a per client 254 * connection basis. The request ID may be useful for logging purposes. 255 * <p> 256 * An internal connection does not require {@code RequestHandler} 257 * implementations to return a result when processing requests. However, it 258 * is recommended that implementations do always return results even for 259 * abandoned requests. This is because application client threads may block 260 * indefinitely waiting for results. 261 * 262 * @param requestHandler 263 * The request handler which will be used for all client 264 * connections. 265 * @return The new internal connection. 266 * @throws NullPointerException 267 * If {@code requestHandler} was {@code null}. 268 */ 269 public static Connection newInternalConnection( 270 final RequestHandler<RequestContext> requestHandler) { 271 Reject.ifNull(requestHandler); 272 return newInternalConnection(adaptRequestHandler(requestHandler)); 273 } 274 275 /** 276 * Creates a new internal client connection which will route requests to the 277 * provided {@code ServerConnection}. 278 * <p> 279 * When processing requests, {@code ServerConnection} implementations are 280 * passed an integer as the first parameter. This integer represents a 281 * pseudo {@code requestID} which is incremented for each successive 282 * internal request on a per client connection basis. The request ID may be 283 * useful for logging purposes. 284 * <p> 285 * An internal connection does not require {@code ServerConnection} 286 * implementations to return a result when processing requests. However, it 287 * is recommended that implementations do always return results even for 288 * abandoned requests. This is because application client threads may block 289 * indefinitely waiting for results. 290 * 291 * @param serverConnection 292 * The server connection. 293 * @return The new internal connection. 294 * @throws NullPointerException 295 * If {@code serverConnection} was {@code null}. 296 */ 297 public static Connection newInternalConnection(final ServerConnection<Integer> serverConnection) { 298 Reject.ifNull(serverConnection); 299 return new InternalConnection(serverConnection); 300 } 301 302 /** 303 * Creates a new connection factory which binds internal client connections 304 * to the provided {@link RequestHandler}s. 305 * <p> 306 * When processing requests, {@code RequestHandler} implementations are 307 * passed an integer as the first parameter. This integer represents a 308 * pseudo {@code requestID} which is incremented for each successive 309 * internal request on a per client connection basis. The request ID may be 310 * useful for logging purposes. 311 * <p> 312 * An internal connection factory does not require {@code RequestHandler} 313 * implementations to return a result when processing requests. However, it 314 * is recommended that implementations do always return results even for 315 * abandoned requests. This is because application client threads may block 316 * indefinitely waiting for results. 317 * 318 * @param requestHandler 319 * The request handler which will be used for all client 320 * connections. 321 * @return The new internal connection factory. 322 * @throws NullPointerException 323 * If {@code requestHandler} was {@code null}. 324 */ 325 public static ConnectionFactory newInternalConnectionFactory( 326 final RequestHandler<RequestContext> requestHandler) { 327 Reject.ifNull(requestHandler); 328 return new InternalConnectionFactory<>( 329 Connections.<Void> newServerConnectionFactory(requestHandler), null); 330 } 331 332 /** 333 * Creates a new connection factory which binds internal client connections 334 * to {@link RequestHandler}s created using the provided 335 * {@link RequestHandlerFactory}. 336 * <p> 337 * When processing requests, {@code RequestHandler} implementations are 338 * passed an integer as the first parameter. This integer represents a 339 * pseudo {@code requestID} which is incremented for each successive 340 * internal request on a per client connection basis. The request ID may be 341 * useful for logging purposes. 342 * <p> 343 * An internal connection factory does not require {@code RequestHandler} 344 * implementations to return a result when processing requests. However, it 345 * is recommended that implementations do always return results even for 346 * abandoned requests. This is because application client threads may block 347 * indefinitely waiting for results. 348 * 349 * @param <C> 350 * The type of client context. 351 * @param factory 352 * The request handler factory to use for creating connections. 353 * @param clientContext 354 * The client context. 355 * @return The new internal connection factory. 356 * @throws NullPointerException 357 * If {@code factory} was {@code null}. 358 */ 359 public static <C> ConnectionFactory newInternalConnectionFactory( 360 final RequestHandlerFactory<C, RequestContext> factory, final C clientContext) { 361 Reject.ifNull(factory); 362 return new InternalConnectionFactory<>(newServerConnectionFactory(factory), clientContext); 363 } 364 365 /** 366 * Creates a new connection factory which binds internal client connections 367 * to {@link ServerConnection}s created using the provided 368 * {@link ServerConnectionFactory}. 369 * <p> 370 * When processing requests, {@code ServerConnection} implementations are 371 * passed an integer as the first parameter. This integer represents a 372 * pseudo {@code requestID} which is incremented for each successive 373 * internal request on a per client connection basis. The request ID may be 374 * useful for logging purposes. 375 * <p> 376 * An internal connection factory does not require {@code ServerConnection} 377 * implementations to return a result when processing requests. However, it 378 * is recommended that implementations do always return results even for 379 * abandoned requests. This is because application client threads may block 380 * indefinitely waiting for results. 381 * 382 * @param <C> 383 * The type of client context. 384 * @param factory 385 * The server connection factory to use for creating connections. 386 * @param clientContext 387 * The client context. 388 * @return The new internal connection factory. 389 * @throws NullPointerException 390 * If {@code factory} was {@code null}. 391 */ 392 public static <C> ConnectionFactory newInternalConnectionFactory( 393 final ServerConnectionFactory<C, Integer> factory, final C clientContext) { 394 Reject.ifNull(factory); 395 return new InternalConnectionFactory<>(factory, clientContext); 396 } 397 398 /** 399 * Creates a new "round-robin" load-balancer which will load-balance connections across the provided set of 400 * connection factories. A round robin load balancing algorithm distributes connection requests across a list of 401 * connection factories one at a time. When the end of the list is reached, the algorithm starts again from the 402 * beginning. 403 * <p/> 404 * This algorithm is typically used for load-balancing <i>within</i> data centers, where load must be distributed 405 * equally across multiple data sources. This algorithm contrasts with the 406 * {@link #newFailoverLoadBalancer(Collection, Options)} which is used for load-balancing <i>between</i> data 407 * centers. 408 * <p/> 409 * If a problem occurs that temporarily prevents connections from being obtained for one of the connection 410 * factories, then this algorithm automatically "fails over" to the next operational connection factory in the list. 411 * If none of the connection factories are operational then a {@code ConnectionException} is returned to the 412 * client. 413 * <p/> 414 * The implementation periodically attempts to connect to failed connection factories in order to determine if they 415 * have become available again. 416 * 417 * @param factories 418 * The connection factories. 419 * @param options 420 * This configuration options for the load-balancer. 421 * @return The new round-robin load balancer. 422 * @see #newShardedRequestLoadBalancer(Collection, Options) 423 * @see #newFailoverLoadBalancer(Collection, Options) 424 * @see #LOAD_BALANCER_EVENT_LISTENER 425 * @see #LOAD_BALANCER_MONITORING_INTERVAL 426 * @see #LOAD_BALANCER_SCHEDULER 427 */ 428 public static ConnectionFactory newRoundRobinLoadBalancer( 429 final Collection<? extends ConnectionFactory> factories, final Options options) { 430 return new ConnectionLoadBalancer("RoundRobinLoadBalancer", factories, options) { 431 private final int maxIndex = factories.size(); 432 private final AtomicInteger nextIndex = new AtomicInteger(-1); 433 434 @Override 435 int getInitialConnectionFactoryIndex() { 436 // A round robin pool of one connection factories is unlikely in 437 // practice and requires special treatment. 438 if (maxIndex == 1) { 439 return 0; 440 } 441 442 // Determine the next factory to use: avoid blocking algorithm. 443 int oldNextIndex; 444 int newNextIndex; 445 do { 446 oldNextIndex = nextIndex.get(); 447 newNextIndex = oldNextIndex + 1; 448 if (newNextIndex == maxIndex) { 449 newNextIndex = 0; 450 } 451 } while (!nextIndex.compareAndSet(oldNextIndex, newNextIndex)); 452 453 // There's a potential, but benign, race condition here: other threads 454 // could jump in and rotate through the list before we return the 455 // connection factory. 456 return newNextIndex; 457 } 458 }; 459 } 460 461 /** 462 * Creates a new "fail-over" load-balancer which will load-balance connections across the provided set of connection 463 * factories. A fail-over load balancing algorithm provides fault tolerance across multiple underlying connection 464 * factories. 465 * <p/> 466 * This algorithm is typically used for load-balancing <i>between</i> data centers, where there is preference to 467 * always forward connection requests to the <i>closest available</i> data center. This algorithm contrasts with the 468 * {@link #newRoundRobinLoadBalancer(Collection, Options)} which is used for load-balancing <i>within</i> a data 469 * center. 470 * <p/> 471 * This algorithm selects connection factories based on the order in which they were provided during construction. 472 * More specifically, an attempt to obtain a connection factory will always return the <i>first operational</i> 473 * connection factory in the list. Applications should, therefore, organize the connection factories such that the 474 * <i>preferred</i> (usually the closest) connection factories appear before those which are less preferred. 475 * <p/> 476 * If a problem occurs that temporarily prevents connections from being obtained for one of the connection 477 * factories, then this algorithm automatically "fails over" to the next operational connection factory in the list. 478 * If none of the connection factories are operational then a {@code ConnectionException} is returned to the 479 * client. 480 * <p/> 481 * The implementation periodically attempts to connect to failed connection factories in order to determine if they 482 * have become available again. 483 * 484 * @param factories 485 * The connection factories. 486 * @param options 487 * This configuration options for the load-balancer. 488 * @return The new fail-over load balancer. 489 * @see #newRoundRobinLoadBalancer(Collection, Options) 490 * @see #newShardedRequestLoadBalancer(Collection, Options) 491 * @see #LOAD_BALANCER_EVENT_LISTENER 492 * @see #LOAD_BALANCER_MONITORING_INTERVAL 493 * @see #LOAD_BALANCER_SCHEDULER 494 */ 495 public static ConnectionFactory newFailoverLoadBalancer( 496 final Collection<? extends ConnectionFactory> factories, final Options options) { 497 return new ConnectionLoadBalancer("FailoverLoadBalancer", factories, options) { 498 @Override 499 int getInitialConnectionFactoryIndex() { 500 // Always start with the first connection factory. 501 return 0; 502 } 503 }; 504 } 505 506 /** 507 * Creates a new "sharded" load-balancer which will load-balance individual requests across the provided set of 508 * connection factories, each typically representing a single replica, using an algorithm that ensures that requests 509 * targeting a given DN will always be routed to the same replica. In other words, this load-balancer increases 510 * consistency whilst maintaining read-scalability by simulating a "single master" replication topology, where each 511 * replica is responsible for a subset of the entries. When a replica is unavailable the load-balancer "fails over" 512 * by performing a linear probe in order to find the next available replica thus ensuring high-availability when a 513 * network partition occurs while sacrificing consistency, since the unavailable replica may still be visible to 514 * other clients. 515 * <p/> 516 * This load-balancer distributes requests based on the hash of their target DN and handles all core operations, as 517 * well as any password modify extended requests and SASL bind requests which use authentication IDs having the 518 * "dn:" form. Note that subtree operations (searches, subtree deletes, and modify DN) are likely to include entries 519 * which are "mastered" on different replicas, so client applications should be more tolerant of inconsistencies. 520 * Requests that are either unrecognized or that do not have a parameter that may be considered to be a target DN 521 * will be routed randomly. 522 * <p/> 523 * <b>NOTE:</b> this connection factory returns fake connections, since real connections are obtained for each 524 * request. Therefore, the returned fake connections have certain limitations: abandon requests will be ignored 525 * since they cannot be routed; connection event listeners can be registered, but will only be notified when the 526 * fake connection is closed or when all of the connection factories are unavailable. 527 * <p/> 528 * <b>NOTE:</b> in deployments where there are multiple client applications, care should be taken to ensure that 529 * the factories are configured using the same ordering, otherwise requests will not be routed consistently 530 * across the client applications. 531 * <p/> 532 * The implementation periodically attempts to connect to failed connection factories in order to determine if they 533 * have become available again. 534 * 535 * @param factories 536 * The connection factories. 537 * @param options 538 * This configuration options for the load-balancer. 539 * @return The new affinity load balancer. 540 * @see #newRoundRobinLoadBalancer(Collection, Options) 541 * @see #newFailoverLoadBalancer(Collection, Options) 542 * @see #LOAD_BALANCER_EVENT_LISTENER 543 * @see #LOAD_BALANCER_MONITORING_INTERVAL 544 * @see #LOAD_BALANCER_SCHEDULER 545 */ 546 public static ConnectionFactory newShardedRequestLoadBalancer( 547 final Collection<? extends ConnectionFactory> factories, final Options options) { 548 return new RequestLoadBalancer("ShardedRequestLoadBalancer", 549 factories, 550 options, 551 newShardedRequestLoadBalancerFunction(factories)); 552 } 553 554 // Package private for testing. 555 static Function<Request, Integer, NeverThrowsException> newShardedRequestLoadBalancerFunction( 556 final Collection<? extends ConnectionFactory> factories) { 557 return new Function<Request, Integer, NeverThrowsException>() { 558 private final int maxIndex = factories.size(); 559 560 @Override 561 public Integer apply(final Request request) { 562 // Normalize the hash to a valid factory index, taking care of negative hash values and especially 563 // Integer.MIN_VALUE (see doc for Math.abs()). 564 final int index = computeIndexBasedOnDnHashCode(request); 565 return index == Integer.MIN_VALUE ? 0 : (Math.abs(index) % maxIndex); 566 } 567 568 private int computeIndexBasedOnDnHashCode(final Request request) { 569 // The following conditions are ordered such that the most common operations appear first in order to 570 // reduce the average number of branches. A better solution would be to use a visitor, but a visitor 571 // would only apply to the core operations, not extended operations or SASL binds. 572 if (request instanceof SearchRequest) { 573 return ((SearchRequest) request).getName().hashCode(); 574 } else if (request instanceof ModifyRequest) { 575 return ((ModifyRequest) request).getName().hashCode(); 576 } else if (request instanceof SimpleBindRequest) { 577 return hashCodeOfDnString(((SimpleBindRequest) request).getName()); 578 } else if (request instanceof AddRequest) { 579 return ((AddRequest) request).getName().hashCode(); 580 } else if (request instanceof DeleteRequest) { 581 return ((DeleteRequest) request).getName().hashCode(); 582 } else if (request instanceof CompareRequest) { 583 return ((CompareRequest) request).getName().hashCode(); 584 } else if (request instanceof ModifyDNRequest) { 585 return ((ModifyDNRequest) request).getName().hashCode(); 586 } else if (request instanceof PasswordModifyExtendedRequest) { 587 return hashCodeOfAuthzid(((PasswordModifyExtendedRequest) request).getUserIdentityAsString()); 588 } else if (request instanceof PlainSASLBindRequest) { 589 return hashCodeOfAuthzid(((PlainSASLBindRequest) request).getAuthenticationID()); 590 } else if (request instanceof DigestMD5SASLBindRequest) { 591 return hashCodeOfAuthzid(((DigestMD5SASLBindRequest) request).getAuthenticationID()); 592 } else if (request instanceof GSSAPISASLBindRequest) { 593 return hashCodeOfAuthzid(((GSSAPISASLBindRequest) request).getAuthenticationID()); 594 } else if (request instanceof CRAMMD5SASLBindRequest) { 595 return hashCodeOfAuthzid(((CRAMMD5SASLBindRequest) request).getAuthenticationID()); 596 } else { 597 return distributeRequestAtRandom(); 598 } 599 } 600 601 private int hashCodeOfAuthzid(final String authzid) { 602 if (authzid != null && authzid.startsWith("dn:")) { 603 return hashCodeOfDnString(authzid.substring(3)); 604 } 605 return distributeRequestAtRandom(); 606 } 607 608 private int hashCodeOfDnString(final String dnString) { 609 try { 610 return DN.valueOf(dnString).hashCode(); 611 } catch (final IllegalArgumentException ignored) { 612 return distributeRequestAtRandom(); 613 } 614 } 615 616 private int distributeRequestAtRandom() { 617 return ThreadLocalRandom.current().nextInt(0, maxIndex); 618 } 619 }; 620 } 621 622 /** 623 * Creates a new connection factory which forwards connection requests to 624 * the provided factory, but whose {@code toString} method will always 625 * return {@code name}. 626 * <p> 627 * This method may be useful for debugging purposes in order to more easily 628 * identity connection factories. 629 * 630 * @param factory 631 * The connection factory to be named. 632 * @param name 633 * The name of the connection factory. 634 * @return The named connection factory. 635 * @throws NullPointerException 636 * If {@code factory} or {@code name} was {@code null}. 637 */ 638 public static ConnectionFactory newNamedConnectionFactory(final ConnectionFactory factory, 639 final String name) { 640 Reject.ifNull(factory, name); 641 642 return new ConnectionFactory() { 643 644 @Override 645 public void close() { 646 factory.close(); 647 } 648 649 @Override 650 public Connection getConnection() throws LdapException { 651 return factory.getConnection(); 652 } 653 654 @Override 655 public Promise<Connection, LdapException> getConnectionAsync() { 656 return factory.getConnectionAsync(); 657 } 658 659 @Override 660 public String toString() { 661 return name; 662 } 663 664 }; 665 } 666 667 /** 668 * Creates a new server connection factory using the provided 669 * {@link RequestHandler}. The returned factory will manage connection and 670 * request life-cycle, including request cancellation. 671 * <p> 672 * When processing requests, {@link RequestHandler} implementations are 673 * passed a {@link RequestContext} as the first parameter which may be used 674 * for detecting whether the request should be aborted due to 675 * cancellation requests or other events, such as connection failure. 676 * <p> 677 * The returned factory maintains state information which includes a table 678 * of active requests. Therefore, {@code RequestHandler} implementations are 679 * required to always return results in order to avoid potential memory 680 * leaks. 681 * 682 * @param <C> 683 * The type of client context. 684 * @param requestHandler 685 * The request handler which will be used for all client 686 * connections. 687 * @return The new server connection factory. 688 * @throws NullPointerException 689 * If {@code requestHandler} was {@code null}. 690 */ 691 public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory( 692 final RequestHandler<RequestContext> requestHandler) { 693 Reject.ifNull(requestHandler); 694 return new RequestHandlerFactoryAdapter<>(new RequestHandlerFactory<C, RequestContext>() { 695 @Override 696 public RequestHandler<RequestContext> handleAccept(final C clientContext) { 697 return requestHandler; 698 } 699 }); 700 } 701 702 /** 703 * Creates a new server connection factory using the provided 704 * {@link RequestHandlerFactory}. The returned factory will manage 705 * connection and request life-cycle, including request cancellation. 706 * <p> 707 * When processing requests, {@link RequestHandler} implementations are 708 * passed a {@link RequestContext} as the first parameter which may be used 709 * for detecting whether the request should be aborted due to 710 * cancellation requests or other events, such as connection failure. 711 * <p> 712 * The returned factory maintains state information which includes a table 713 * of active requests. Therefore, {@code RequestHandler} implementations are 714 * required to always return results in order to avoid potential memory 715 * leaks. 716 * 717 * @param <C> 718 * The type of client context. 719 * @param factory 720 * The request handler factory to use for associating request 721 * handlers with client connections. 722 * @return The new server connection factory. 723 * @throws NullPointerException 724 * If {@code factory} was {@code null}. 725 */ 726 public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory( 727 final RequestHandlerFactory<C, RequestContext> factory) { 728 Reject.ifNull(factory); 729 return new RequestHandlerFactoryAdapter<>(factory); 730 } 731 732 /** 733 * Returns an uncloseable view of the provided connection. Attempts to call 734 * {@link Connection#close()} or 735 * {@link Connection#close(org.forgerock.opendj.ldap.requests.UnbindRequest, String)} 736 * will be ignored. 737 * 738 * @param connection 739 * The connection whose {@code close} methods are to be disabled. 740 * @return An uncloseable view of the provided connection. 741 */ 742 public static Connection uncloseable(Connection connection) { 743 return new AbstractConnectionWrapper<Connection>(connection) { 744 @Override 745 public void close() { 746 // Do nothing. 747 } 748 749 @Override 750 public void close(org.forgerock.opendj.ldap.requests.UnbindRequest request, 751 String reason) { 752 // Do nothing. 753 } 754 }; 755 } 756 757 /** 758 * Returns an uncloseable view of the provided connection factory. Attempts 759 * to call {@link ConnectionFactory#close()} will be ignored. 760 * 761 * @param factory 762 * The connection factory whose {@code close} method is to be 763 * disabled. 764 * @return An uncloseable view of the provided connection factory. 765 */ 766 public static ConnectionFactory uncloseable(final ConnectionFactory factory) { 767 return new ConnectionFactory() { 768 769 @Override 770 public Promise<Connection, LdapException> getConnectionAsync() { 771 return factory.getConnectionAsync(); 772 } 773 774 @Override 775 public Connection getConnection() throws LdapException { 776 return factory.getConnection(); 777 } 778 779 @Override 780 public void close() { 781 // Do nothing. 782 } 783 }; 784 } 785 786 /** 787 * Returns the host name associated with the provided 788 * {@code InetSocketAddress}, without performing a DNS lookup. This method 789 * attempts to provide functionality which is compatible with 790 * {@code InetSocketAddress.getHostString()} in JDK7. It can be removed once 791 * we drop support for JDK6. 792 * 793 * @param socketAddress 794 * The socket address which is expected to be an instance of 795 * {@code InetSocketAddress}. 796 * @return The host name associated with the provided {@code SocketAddress}, 797 * or {@code null} if it is unknown. 798 */ 799 public static String getHostString(final InetSocketAddress socketAddress) { 800 /* 801 * See OPENDJ-1270 for more information about slow DNS queries. 802 * 803 * We must avoid calling getHostName() in the case where it is likely to 804 * perform a blocking DNS query. Ideally we would call getHostString(), 805 * but the method was only added in JDK7. 806 */ 807 if (socketAddress.isUnresolved()) { 808 /* 809 * Usually socket addresses are resolved on creation. If the address 810 * is unresolved then there must be a user provided hostname instead 811 * and getHostName will not perform a reverse lookup. 812 */ 813 return socketAddress.getHostName(); 814 } else { 815 /* 816 * Simulate getHostString() by parsing the toString() 817 * representation. This assumes that the toString() representation 818 * is stable, which I assume it is because it is documented. 819 */ 820 final InetAddress address = socketAddress.getAddress(); 821 final String hostSlashIp = address.toString(); 822 final int slashPos = hostSlashIp.indexOf('/'); 823 if (slashPos == 0) { 824 return hostSlashIp.substring(1); 825 } else { 826 return hostSlashIp.substring(0, slashPos); 827 } 828 } 829 } 830 831 /** Prevent instantiation. */ 832 private Connections() { 833 // Do nothing. 834 } 835}