001/* 002 * Copyright 2014-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk.unboundidds.controls; 022 023 024 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.LinkedHashSet; 030import java.util.Set; 031 032import com.unboundid.asn1.ASN1Element; 033import com.unboundid.asn1.ASN1OctetString; 034import com.unboundid.asn1.ASN1Sequence; 035import com.unboundid.asn1.ASN1Set; 036import com.unboundid.ldap.sdk.Control; 037import com.unboundid.ldap.sdk.LDAPException; 038import com.unboundid.ldap.sdk.ResultCode; 039import com.unboundid.util.Debug; 040import com.unboundid.util.NotMutable; 041import com.unboundid.util.StaticUtils; 042import com.unboundid.util.ThreadSafety; 043import com.unboundid.util.ThreadSafetyLevel; 044import com.unboundid.util.Validator; 045 046import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 047 048 049 050/** 051 * This class provides a request control which may be used to request that the 052 * Directory Proxy Server forward the associated operation to a specific backend 053 * set associated with an entry-balancing request processor. It may be either 054 * an absolute routing request, indicating that the target backend set(s) are 055 * the only ones that may be used to process the operation, or it may be used to 056 * provide a routing hint in lieu of accessing the global index. 057 * <BR> 058 * <BLOCKQUOTE> 059 * <B>NOTE:</B> This class, and other classes within the 060 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 061 * supported for use against Ping Identity, UnboundID, and 062 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 063 * for proprietary functionality or for external specifications that are not 064 * considered stable or mature enough to be guaranteed to work in an 065 * interoperable way with other types of LDAP servers. 066 * </BLOCKQUOTE> 067 * <BR> 068 * This control may be used for a number of different kinds of requests, as 069 * follows: 070 * <UL> 071 * <LI>For an add request that uses absolute routing, exactly one target 072 * backend set ID must be specified, and the request will be sent only to 073 * that backend set. 074 * <BR> 075 * <B>WARNING</B>: The use of absolute routing for an add 076 * operation bypasses the check to ensure that no entry already exists 077 * with the same DN as the new entry, so it is possible that an add 078 * performed immediately below the balancing point could result in 079 * creating an entry in one backend set with the same DN as another entry 080 * in a different backend set. Similarly, if the entry-balancing request 081 * processor is configured to broadcast add operations outside the 082 * balancing point rather than relying on those adds to be replicated, 083 * then it is strongly recommended that absolute routing not be used for 084 * add operations outside the balancing point because that will cause the 085 * entry to be added to only one backend set rather than to all backend 086 * sets.</LI> 087 * <LI>For an add request that uses a routing hint, exactly one target backend 088 * set ID must be specified for the first guess, although any number of 089 * fallback set IDs may be specified. For entries immediately below the 090 * balancing point, the routing hint will be used instead of a placement 091 * algorithm in order to select which backend set should hold the entry 092 * (and the fallback sets will not be used). For entries more than one 093 * level below the balancing point, the routing hint will be used in lieu 094 * of the global index as an attempt to determine where the parent entry 095 * exists, and the fallback sets may be used if the parent entry doesn't 096 * exist in the first guess set. For entries outside the balancing point, 097 * if the entry-balancing request processor is configured to add entries 098 * to one set and allow them to be replicated to other sets, then the 099 * first guess hint will be used to select the set to which the entry will 100 * be added (and the fallback sets will not be used). An add operation 101 * with a routing hint cannot be used to create multiple entries with the 102 * same DN in different backend sets, nor can it cause an entry outside 103 * the balancing point to exist in only one backend set.</LI> 104 * <LI>For a simple bind request that uses absolute routing, exactly one 105 * target backend set ID must be specified, and the request will be sent 106 * only to that backend set. If the bind fails in that set, even if the 107 * failure is because the target entry does not exist in that backend set, 108 * then the failure will be returned to the client rather than attempting 109 * the operation in a different backend set.</LI> 110 * <LI>For a simple bind request that uses a routing hint, exactly one target 111 * backend set ID must be specified for the first guess, although any 112 * number of fallback set IDs may be specified. If the bind fails in the 113 * first guess set, it may be re-attempted in the fallback sets.</LI> 114 * <LI>For a compare request that uses absolute routing, exactly one target 115 * backend set ID must be specified, and the request will be sent only to 116 * that backend set. If the compare fails in that set, even if the 117 * failure is because the target entry does not exist in that set, then 118 * the failure will be returned to the client rather than attempting the 119 * operation in a different backend set.</LI> 120 * <LI>For a compare request that uses a routing hint, exactly one target 121 * backend set ID must be specified for the first guess, although any 122 * number of fallback set IDs may be specified. If the compare operation 123 * fails in the first guess set in a way that suggests the target entry 124 * does not exist in that backend set, then it will be re-attempted in the 125 * fallback sets.</LI> 126 * <LI>For a delete request that uses absolute routing, exactly one target 127 * backend set ID must be specified, and the request will be sent only to 128 * that backend set. If the delete fails in that set, even if the failure 129 * is because the target entry does not exist in that set, then the 130 * failure will be returned to the client rather than attempting the 131 * operation in a different backend set. 132 * <BR> 133 * <B>WARNING</B>: If the entry-balancing request processor is configured 134 * to broadcast delete operations outside the balancing point rather than 135 * relying on those deletes to be replicated, then it is strongly 136 * recommended that absolute routing not be used for delete operations 137 * outside the balancing point because that will cause the entry to be 138 * deleted in only one backend set and will remain in all other backend 139 * sets.</LI> 140 * <LI>For a delete request that uses a routing hint, exactly one target 141 * backend set ID must be specified for the first guess, although any 142 * number of fallback set IDs may be specified. For entries below the 143 * balancing point, the routing hint will be used in lieu of the global 144 * index in order to determine which backend set contains the target 145 * entry. If the delete fails in the first guess set in a way that 146 * suggests that the target entry does not exist in that backend set, then 147 * it will be re-attempted in the fallback sets. 148 * <BR> 149 * For entries outside the balancing point, if the entry-balancing request 150 * processor is configured to delete entries from only one backend set 151 * and allow that delete to be replicated to all other sets, then the 152 * routing hint may be used to select the set from which that entry will 153 * be deleted. A delete operation with a routing hint cannot be used to 154 * cause an entry outside the balancing point to be removed from only one 155 * backend set while leaving it in the remaining sets.</LI> 156 * <LI>For an atomic multi-update extended request, only absolute routing is 157 * supported, and the route to backend set request control must be 158 * attached to the extended operation itself and not to any of the 159 * requests contained inside the multi-update. Exactly one backend set ID 160 * must be specified, and the multi-update request will be sent only to 161 * that backend set.</LI> 162 * <LI>For a non-atomic multi-update extended request, the extended operation 163 * must not include a route to backend set request control. However, any 164 * or all of the requests inside the multi-update request may include a 165 * route to backend set request control, and in that case it will be 166 * treated in the same way as for a request of the same type not 167 * included in multi-update request (e.g., if a multi-update extended 168 * operation includes an add request with a route to backend set request 169 * control, then that route control will have the same effect as for the 170 * same add request with the same control processed outside a multi-update 171 * operation).</LI> 172 * <LI>For an extended request that will be processed by a proxied extended 173 * operation handler, the request may include a route to backend set 174 * request control and that control will be used to select the target 175 * backend sets instead of the proxied extended operation handler's 176 * {@code selectBackendSets} method.</LI> 177 * <LI>For a modify request that uses absolute routing, exactly one target 178 * backend set ID must be specified, and the request will be sent only to 179 * that backend set. If the modify fails in that set, even if the failure 180 * is because the target entry does not exist in that set, then the 181 * failure will be returned to the client rather than attempting the 182 * operation in a different backend set. 183 * <BR> 184 * <B>WARNING</B>: When processing a modify operation against the 185 * balancing point entry itself, the Directory Proxy Server will typically 186 * send that modify request to all backend sets to ensure that it is 187 * properly applied everywhere. However, with an absolute routing 188 * request, the modify operation will be sent only to one backend set, 189 * which will cause the entry in that set to be out of sync with the entry 190 * in all other sets. It is therefore strongly recommended that absolute 191 * routing not be used for modify operations that target the balancing 192 * point entry. Similarly, if the entry-balancing request processor is 193 * configured to broadcast modify operations targeting entries outside the 194 * balancing point to all backend sets rather than having those modify 195 * operations replicated to the other backend sets, it is strongly 196 * recommended that absolute routing not be used for those operations 197 * because the request will be sent to only one set, causing the entry in 198 * that set to be out of sync with the corresponding entry in other 199 * backend sets.</LI> 200 * <LI>For a modify request that uses a routing hint, exactly one target 201 * backend set ID must be specified for the first guess, although any 202 * number of fallback set IDs may be specified. For entries below the 203 * balancing point, the routing hint will be used in lieu of the global 204 * index in order to determine which backend set contains the target 205 * entry. If the modify attempt fails in the first guess set in a way 206 * that suggests the target entry does not exist in that backend set, then 207 * it will be re-attempted in the fallback sets. 208 * <BR> 209 * For modify operations that target the balancing point entry itself, the 210 * entry-balancing request processor will send the request to all backend 211 * sets, and the routing hint will not be used. Similarly, for entries 212 * outside the balancing point, if the entry-balancing request processor 213 * is configured to modify entries in only one backend set and allow that 214 * modify operation to be replicated to all other sets, then the routing 215 * hint may be used to select the set in which that entry will be 216 * modified. A modify operation with a routing hint cannot be used to 217 * cause an entry at or outside the balancing point to be updated in only 218 * one backend set, leaving it out of sync with the corresponding entry in 219 * the remaining sets.</LI> 220 * <LI>For a modify DN request that uses absolute routing, exactly one target 221 * backend set ID must be specified, and the request wil be sent only to 222 * that backend set. If the modify DN operation fails in that set, even 223 * if the failure is because the target entry does not exist in that set, 224 * then the failure will be returned to the client rather than attempting 225 * the operation in a different backend set. 226 * <BR> 227 * <B>WARNING</B>: Processing a modify DN operation with absolute routing 228 * bypasses the check to ensure that the new DN for the target entry does 229 * not conflict with the DN for an entry that exists in any other backend 230 * set. As a result, you are strongly discouraged from using absolute 231 * routing for any modify DN operation that would cause the new DN for the 232 * entry to be exactly one level below the balancing point. Further, for 233 * entries that exist outside the balancing point, if the entry-balancing 234 * request processor is configured to broadcast modify DN operations 235 * rather than expecting them to be replicated to the other backend sets, 236 * a modify DN operation with absolute routing would cause the change to 237 * be applied only in one backend set, leaving it out of sync with the 238 * other sets.</LI> 239 * <LI>For a modify DN request that uses a routing hint, exactly one target 240 * backend set ID must be specified for the first guess, although any 241 * number of fallback set IDs may be specified. For entries below the 242 * balancing point, the routing hint will be used in lieu of the global 243 * index in order to determine which backend set contains the target 244 * entry. If the modify attempt fails in the first guess set in a way 245 * that suggests the target entry does not exist in that backend set, then 246 * it will be re-attempted in the fallback sets. 247 * <BR> 248 * For entries outside the balancing point, if the entry-balancing request 249 * processor is configured to process modify DN operations in one backend 250 * set and allow them to be replicated to other backend sets, then the 251 * routing hint will be used to select which backend set should receive 252 * the modify DN request. A modify DN operation with a routing hint 253 * cannot be used to create a conflict in which the same DN exists in 254 * multiple backend sets, or a case in which a modify DN operation outside 255 * the balancing point leaves one backend set out of sync with the other 256 * sets.</LI> 257 * <LI>For a search request that uses absolute routing, there may be multiple 258 * target backend set IDs only if the scope of the search may include 259 * data from multiple backend sets (i.e., the base DN is at or above the 260 * balancing point, and the scope include entries at least one level below 261 * the balancing point entry). If the base and scope of the search allow 262 * it to match only entries at or above the balancing point or only 263 * entries within one backend set, then the absolute routing request must 264 * target exactly one backend set.</LI> 265 * <LI>For a search request that uses a routing hint, exactly one target 266 * backend set ID must be specified for the first guess, although any 267 * number of fallback set IDs may be specified. The routing hint will 268 * only be used for cases in which the entire scope of the search is 269 * contained entirely within a backend set (i.e., the entire scope is 270 * at or above the balancing point, or the entire scope is at least one 271 * level below the balancing point).</LI> 272 * </UL> 273 * <BR><BR> 274 * The OID for a route to backend set request control is 275 * "1.3.6.1.4.1.30221.2.5.35", and the criticality may be either {@code true} or 276 * {@code false}. It must have a value with the following encoding: 277 * <PRE> 278 * RouteToBackendSetRequest ::= SEQUENCE { 279 * entryBalancingRequestProcessorID OCTET STRING, 280 * backendSets CHOICE { 281 * absoluteRoutingRequest [0] SET OF OCTET STRING, 282 * routingHint [1] SEQUENCE { 283 * firstGuessSetIDs SET OF OCTET STRING, 284 * fallbackSetIDs SET OF OCTET STRING OPTIONAL } 285 * ... } 286 * ... } 287 * </PRE> 288 * The use of the route to backend set request control will also cause the 289 * server to behave as if the get backend set ID request control had been 290 * included, so that the get backend set ID response control may be included in 291 * operation result and search result entry messages as appropriate. 292 */ 293@NotMutable() 294@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 295public final class RouteToBackendSetRequestControl 296 extends Control 297{ 298 /** 299 * The OID (1.3.6.1.4.1.30221.2.5.35) for the route to server request control. 300 */ 301 public static final String ROUTE_TO_BACKEND_SET_REQUEST_OID = 302 "1.3.6.1.4.1.30221.2.5.35"; 303 304 305 306 /** 307 * The serial version UID for this serializable class. 308 */ 309 private static final long serialVersionUID = -2486448910813783450L; 310 311 312 313 // The routing type for the request. 314 private final RouteToBackendSetRoutingType routingType; 315 316 // The backend set IDs for an absolute routing request. 317 private final Set<String> absoluteBackendSetIDs; 318 319 // The backend set IDs for the fallback sets of a routing hint. 320 private final Set<String> routingHintFallbackSetIDs; 321 322 // The backend set IDs for the first guess of a routing hint. 323 private final Set<String> routingHintFirstGuessSetIDs; 324 325 // The identifier for the entry-balancing request processor with which the 326 // backend set IDs are associated. 327 private final String entryBalancingRequestProcessorID; 328 329 330 331 /** 332 * Creates a new route to backend set request control with the provided 333 * information. 334 * 335 * @param isCritical Indicates whether this control 336 * should be critical. 337 * @param encodedValue The encoded value for this 338 * control. It must not be 339 * {@code null}. 340 * @param entryBalancingRequestProcessorID The identifier for the 341 * entry-balancing request processor 342 * with which the backend set IDs 343 * are associated. It must not be 344 * {@code null}. 345 * @param routingType The routing type for this 346 * request. It must not be 347 * {@code null}. 348 * @param absoluteBackendSetIDs The collection of backend sets to 349 * which the request should be sent 350 * for an absolute routing request. 351 * It must be non-{@code null} and 352 * non-empty for an absolute routing 353 * request, and must be {@code null} 354 * for a routing hint. 355 * @param routingHintFirstGuessSetIDs The collection of backend sets 356 * that should be used as the first 357 * guess for a routing hint request. 358 * It must be {@code null} for an 359 * absolute routing request, and 360 * must be non-{@code null} and 361 * non-empty for a routing hint. 362 * @param routingHintFallbackSetIDs The collection of fallback 363 * backend sets that should be used 364 * for a routing hint request if the 365 * first guess was unsuccessful. It 366 * must be {@code null} for an 367 * absolute routing request, and may 368 * be {@code null} for a routing 369 * hint if the fallback sets should 370 * be all backend sets for the 371 * entry-balancing request processor 372 * that were not included in the 373 * first guess. If it is 374 * non-{@code null}, then it must 375 * also be non-empty. 376 */ 377 private RouteToBackendSetRequestControl(final boolean isCritical, 378 final ASN1OctetString encodedValue, 379 final String entryBalancingRequestProcessorID, 380 final RouteToBackendSetRoutingType routingType, 381 final Collection<String> absoluteBackendSetIDs, 382 final Collection<String> routingHintFirstGuessSetIDs, 383 final Collection<String> routingHintFallbackSetIDs) 384 { 385 super(ROUTE_TO_BACKEND_SET_REQUEST_OID, isCritical, encodedValue); 386 387 this.entryBalancingRequestProcessorID = entryBalancingRequestProcessorID; 388 this.routingType = routingType; 389 390 if (absoluteBackendSetIDs == null) 391 { 392 this.absoluteBackendSetIDs = null; 393 } 394 else 395 { 396 this.absoluteBackendSetIDs = Collections.unmodifiableSet( 397 new LinkedHashSet<>(absoluteBackendSetIDs)); 398 } 399 400 if (routingHintFirstGuessSetIDs == null) 401 { 402 this.routingHintFirstGuessSetIDs = null; 403 } 404 else 405 { 406 this.routingHintFirstGuessSetIDs = Collections.unmodifiableSet( 407 new LinkedHashSet<>(routingHintFirstGuessSetIDs)); 408 } 409 410 if (routingHintFallbackSetIDs == null) 411 { 412 this.routingHintFallbackSetIDs = null; 413 } 414 else 415 { 416 this.routingHintFallbackSetIDs = Collections.unmodifiableSet( 417 new LinkedHashSet<>(routingHintFallbackSetIDs)); 418 } 419 } 420 421 422 423 /** 424 * Creates a new route to backend set request control that is decoded from the 425 * provided generic control. 426 * 427 * @param control The control to decode as a route to backend set request 428 * control. 429 * 430 * @throws LDAPException If the provided control cannot be decoded as a 431 * route to backend set request control. 432 */ 433 public RouteToBackendSetRequestControl(final Control control) 434 throws LDAPException 435 { 436 super(control); 437 438 final ASN1OctetString value = control.getValue(); 439 if (value == null) 440 { 441 throw new LDAPException(ResultCode.DECODING_ERROR, 442 ERR_ROUTE_TO_BACKEND_SET_REQUEST_MISSING_VALUE.get()); 443 } 444 445 try 446 { 447 final ASN1Element[] elements = 448 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 449 entryBalancingRequestProcessorID = 450 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 451 452 routingType = RouteToBackendSetRoutingType.valueOf(elements[1].getType()); 453 if (routingType == null) 454 { 455 throw new LDAPException(ResultCode.DECODING_ERROR, 456 ERR_ROUTE_TO_BACKEND_SET_REQUEST_UNKNOWN_ROUTING_TYPE.get( 457 StaticUtils.toHex(elements[1].getType()))); 458 } 459 460 if (routingType == RouteToBackendSetRoutingType.ABSOLUTE_ROUTING) 461 { 462 final ASN1Element[] arElements = 463 ASN1Set.decodeAsSet(elements[1]).elements(); 464 final LinkedHashSet<String> arSet = 465 new LinkedHashSet<>(arElements.length); 466 for (final ASN1Element e : arElements) 467 { 468 arSet.add(ASN1OctetString.decodeAsOctetString(e).stringValue()); 469 } 470 absoluteBackendSetIDs = Collections.unmodifiableSet(arSet); 471 if (absoluteBackendSetIDs.isEmpty()) 472 { 473 throw new LDAPException(ResultCode.DECODING_ERROR, 474 ERR_ROUTE_TO_BACKEND_SET_REQUEST_ABSOLUTE_SET_EMPTY.get()); 475 } 476 477 routingHintFirstGuessSetIDs = null; 478 routingHintFallbackSetIDs = null; 479 } 480 else 481 { 482 final ASN1Element[] hintElements = 483 ASN1Sequence.decodeAsSequence(elements[1]).elements(); 484 485 final ASN1Element[] firstGuessElements = 486 ASN1Set.decodeAsSet(hintElements[0]).elements(); 487 final LinkedHashSet<String> firstGuessSet = 488 new LinkedHashSet<>(firstGuessElements.length); 489 for (final ASN1Element e : firstGuessElements) 490 { 491 firstGuessSet.add( 492 ASN1OctetString.decodeAsOctetString(e).stringValue()); 493 } 494 routingHintFirstGuessSetIDs = 495 Collections.unmodifiableSet(firstGuessSet); 496 if (routingHintFirstGuessSetIDs.isEmpty()) 497 { 498 throw new LDAPException(ResultCode.DECODING_ERROR, 499 ERR_ROUTE_TO_BACKEND_SET_REQUEST_HINT_FIRST_SET_EMPTY.get()); 500 } 501 502 if (hintElements.length == 1) 503 { 504 routingHintFallbackSetIDs = null; 505 } 506 else 507 { 508 final ASN1Element[] fallbackElements = 509 ASN1Set.decodeAsSet(hintElements[1]).elements(); 510 final LinkedHashSet<String> fallbackSet = 511 new LinkedHashSet<>(fallbackElements.length); 512 for (final ASN1Element e : fallbackElements) 513 { 514 fallbackSet.add( 515 ASN1OctetString.decodeAsOctetString(e).stringValue()); 516 } 517 routingHintFallbackSetIDs = Collections.unmodifiableSet(fallbackSet); 518 if (routingHintFallbackSetIDs.isEmpty()) 519 { 520 throw new LDAPException(ResultCode.DECODING_ERROR, 521 ERR_ROUTE_TO_BACKEND_SET_REQUEST_HINT_FALLBACK_SET_EMPTY. 522 get()); 523 } 524 } 525 526 absoluteBackendSetIDs = null; 527 } 528 } 529 catch (final LDAPException le) 530 { 531 Debug.debugException(le); 532 throw le; 533 } 534 catch (final Exception e) 535 { 536 Debug.debugException(e); 537 throw new LDAPException(ResultCode.DECODING_ERROR, 538 ERR_ROUTE_TO_BACKEND_SET_REQUEST_CANNOT_DECODE.get( 539 StaticUtils.getExceptionMessage(e)), 540 e); 541 } 542 } 543 544 545 546 /** 547 * Creates a new route to backend set request control that may be used for 548 * absolute routing to the specified backend set. 549 * 550 * @param isCritical Indicates whether the control 551 * should be marked critical. 552 * @param entryBalancingRequestProcessorID The identifier for the 553 * entry-balancing request processor 554 * with which the backend set ID 555 * is associated. It must not be 556 * {@code null}. 557 * @param backendSetID The backend set ID for the 558 * backend set to which the request 559 * should be forwarded. It must not 560 * be {@code null}. 561 * 562 * @return The route to backend set request control created from the 563 * provided information. 564 */ 565 public static RouteToBackendSetRequestControl createAbsoluteRoutingRequest( 566 final boolean isCritical, 567 final String entryBalancingRequestProcessorID, 568 final String backendSetID) 569 { 570 return createAbsoluteRoutingRequest(isCritical, 571 entryBalancingRequestProcessorID, 572 Collections.singletonList(backendSetID)); 573 } 574 575 576 577 /** 578 * Creates a new route to backend set request control that may be used for 579 * absolute routing to the specified collection of backend sets. 580 * 581 * @param isCritical Indicates whether the control 582 * should be marked critical. 583 * @param entryBalancingRequestProcessorID The identifier for the 584 * entry-balancing request processor 585 * with which the backend set IDs 586 * are associated. It must not be 587 * {@code null}. 588 * @param backendSetIDs The backend set IDs for the 589 * backend sets to which the request 590 * should be forwarded. It must not 591 * be {@code null} or empty. 592 * 593 * @return The route to backend set request control created from the 594 * provided information. 595 */ 596 public static RouteToBackendSetRequestControl createAbsoluteRoutingRequest( 597 final boolean isCritical, 598 final String entryBalancingRequestProcessorID, 599 final Collection<String> backendSetIDs) 600 { 601 Validator.ensureNotNull(backendSetIDs); 602 Validator.ensureFalse(backendSetIDs.isEmpty()); 603 604 final ArrayList<ASN1Element> backendSetIDElements = 605 new ArrayList<>(backendSetIDs.size()); 606 for (final String s : backendSetIDs) 607 { 608 backendSetIDElements.add(new ASN1OctetString(s)); 609 } 610 611 final RouteToBackendSetRoutingType routingType = 612 RouteToBackendSetRoutingType.ABSOLUTE_ROUTING; 613 final ASN1Sequence valueSequence = new ASN1Sequence( 614 new ASN1OctetString(entryBalancingRequestProcessorID), 615 new ASN1Set(routingType.getBERType(), backendSetIDElements)); 616 617 return new RouteToBackendSetRequestControl(isCritical, 618 new ASN1OctetString(valueSequence.encode()), 619 entryBalancingRequestProcessorID, routingType, backendSetIDs, null, 620 null); 621 } 622 623 624 625 /** 626 * Creates a new route to backend set request control that may be used to 627 * provide a hint as to the backend set to which the operation should be 628 * forwarded, and an optional specification of fallback sets. 629 * 630 * @param isCritical Indicates whether the control 631 * should be marked critical. 632 * @param entryBalancingRequestProcessorID The identifier for the 633 * entry-balancing request processor 634 * with which the backend set IDs 635 * are associated. It must not be 636 * {@code null}. 637 * @param firstGuessSetID The backend set ID for the 638 * backend set to try first. It 639 * must not be {@code null}. 640 * @param fallbackSetIDs The backend set ID(s) for the 641 * backend set(s) to use if none of 642 * the servers in the first guess 643 * set returns a success result. 644 * If this is {@code null}, then the 645 * server will use a default 646 * fallback set of all backend sets 647 * except for the first guess set. 648 * If this is not {@code null}, then 649 * it must also be non-empty. 650 * 651 * @return The route to backend set request control created from the 652 * provided information. 653 */ 654 public static RouteToBackendSetRequestControl createRoutingHintRequest( 655 final boolean isCritical, 656 final String entryBalancingRequestProcessorID, 657 final String firstGuessSetID, 658 final Collection<String> fallbackSetIDs) 659 { 660 return createRoutingHintRequest(isCritical, 661 entryBalancingRequestProcessorID, 662 Collections.singletonList(firstGuessSetID), 663 fallbackSetIDs); 664 } 665 666 667 668 /** 669 * Creates a new route to backend set request control that may be used to 670 * provide a hint as to the backend set(s) to which the operation should be 671 * forwarded, and an optional specification of fallback sets. 672 * 673 * @param isCritical Indicates whether the control 674 * should be marked critical. 675 * @param entryBalancingRequestProcessorID The identifier for the 676 * entry-balancing request processor 677 * with which the backend set IDs 678 * are associated. It must not be 679 * {@code null}. 680 * @param firstGuessSetIDs The backend set ID(s) for the 681 * backend set(s) to try first. It 682 * must not be {@code null} or 683 * empty. 684 * @param fallbackSetIDs The backend set ID(s) for the 685 * backend set(s) to use if none of 686 * the servers in the first guess 687 * set returns a success result. 688 * If this is {@code null}, then the 689 * server will use a default 690 * fallback set of all backend sets 691 * not included in the first guess. 692 * If this is not {@code null}, then 693 * it must also be non-empty. 694 * 695 * @return The route to backend set request control created from the 696 * provided information. 697 */ 698 public static RouteToBackendSetRequestControl createRoutingHintRequest( 699 final boolean isCritical, 700 final String entryBalancingRequestProcessorID, 701 final Collection<String> firstGuessSetIDs, 702 final Collection<String> fallbackSetIDs) 703 { 704 Validator.ensureNotNull(firstGuessSetIDs); 705 Validator.ensureFalse(firstGuessSetIDs.isEmpty()); 706 707 if (fallbackSetIDs != null) 708 { 709 Validator.ensureFalse(fallbackSetIDs.isEmpty()); 710 } 711 712 final ArrayList<ASN1Element> backendSetsElements = new ArrayList<>(2); 713 final ArrayList<ASN1Element> firstGuessElements = 714 new ArrayList<>(firstGuessSetIDs.size()); 715 for (final String s : firstGuessSetIDs) 716 { 717 firstGuessElements.add(new ASN1OctetString(s)); 718 } 719 backendSetsElements.add(new ASN1Set(firstGuessElements)); 720 721 if (fallbackSetIDs != null) 722 { 723 final ArrayList<ASN1Element> fallbackElements = 724 new ArrayList<>(fallbackSetIDs.size()); 725 for (final String s : fallbackSetIDs) 726 { 727 fallbackElements.add(new ASN1OctetString(s)); 728 } 729 backendSetsElements.add(new ASN1Set(fallbackElements)); 730 } 731 732 final RouteToBackendSetRoutingType routingType = 733 RouteToBackendSetRoutingType.ROUTING_HINT; 734 final ASN1Sequence valueSequence = new ASN1Sequence( 735 new ASN1OctetString(entryBalancingRequestProcessorID), 736 new ASN1Sequence(routingType.getBERType(), backendSetsElements)); 737 738 return new RouteToBackendSetRequestControl(isCritical, 739 new ASN1OctetString(valueSequence.encode()), 740 entryBalancingRequestProcessorID, routingType, null, firstGuessSetIDs, 741 fallbackSetIDs); 742 } 743 744 745 746 /** 747 * Retrieves the identifier for the entry-balancing request processor with 748 * which the backend set IDs are associated. 749 * 750 * @return The identifier for the entry-balancing request processor with 751 * which the backend set IDs are associated. 752 */ 753 public String getEntryBalancingRequestProcessorID() 754 { 755 return entryBalancingRequestProcessorID; 756 } 757 758 759 760 /** 761 * Retrieves the type of routing requested by this control. 762 * 763 * @return The type of routing requested by this control. 764 */ 765 public RouteToBackendSetRoutingType getRoutingType() 766 { 767 return routingType; 768 } 769 770 771 772 /** 773 * Retrieves the collection of backend set IDs for the backend sets to which 774 * the request should be forwarded if the control uses absolute routing. 775 * 776 * @return The collection of backend set IDs for the backend sets to which 777 * the request should be forwarded if the control uses absolute 778 * routing, or {@code null} if the control uses a routing hint. 779 */ 780 public Set<String> getAbsoluteBackendSetIDs() 781 { 782 return absoluteBackendSetIDs; 783 } 784 785 786 787 /** 788 * Retrieves the collection of backend set IDs for the first guess of backend 789 * sets to which the request should be forwarded if the control uses a routing 790 * hint. 791 * 792 * @return The collection of backend set IDs for the first guess of backend 793 * sets to which the request should be forwarded if the control uses 794 * a routing hint, or {@code null} if the control uses absolute 795 * routing. 796 */ 797 public Set<String> getRoutingHintFirstGuessSetIDs() 798 { 799 return routingHintFirstGuessSetIDs; 800 } 801 802 803 804 /** 805 * Retrieves the collection of backend set IDs to which the request should be 806 * forwarded if the control uses a routing hint and an explicit group of 807 * fallback sets was specified. 808 * 809 * @return The collection of backend set IDs to which the request should be 810 * forwarded if the control uses a routing hint and an explicit 811 * group of fallback sets was specified, or {@code null} if the 812 * control uses absolute routing or if a default group of fallback 813 * sets (all sets not included in the first guess) should be used. 814 */ 815 public Set<String> getRoutingHintFallbackSetIDs() 816 { 817 return routingHintFallbackSetIDs; 818 } 819 820 821 822 /** 823 * {@inheritDoc} 824 */ 825 @Override() 826 public String getControlName() 827 { 828 return INFO_CONTROL_NAME_ROUTE_TO_BACKEND_SET_REQUEST.get(); 829 } 830 831 832 833 /** 834 * {@inheritDoc} 835 */ 836 @Override() 837 public void toString(final StringBuilder buffer) 838 { 839 buffer.append("RouteToBackendSetRequestControl(isCritical="); 840 buffer.append(isCritical()); 841 buffer.append(", entryBalancingRequestProcessorID='"); 842 buffer.append(entryBalancingRequestProcessorID); 843 buffer.append("', routingType='"); 844 845 Iterator<String> iterator = null; 846 switch (routingType) 847 { 848 case ABSOLUTE_ROUTING: 849 buffer.append("absolute', backendSetIDs={"); 850 iterator = absoluteBackendSetIDs.iterator(); 851 while (iterator.hasNext()) 852 { 853 buffer.append('\''); 854 buffer.append(iterator.next()); 855 buffer.append('\''); 856 857 if (iterator.hasNext()) 858 { 859 buffer.append(", "); 860 } 861 } 862 buffer.append('}'); 863 break; 864 865 case ROUTING_HINT: 866 buffer.append("hint', firstGuessSetIDs={"); 867 iterator = routingHintFirstGuessSetIDs.iterator(); 868 while (iterator.hasNext()) 869 { 870 buffer.append('\''); 871 buffer.append(iterator.next()); 872 buffer.append('\''); 873 874 if (iterator.hasNext()) 875 { 876 buffer.append(", "); 877 } 878 } 879 buffer.append('}'); 880 881 if (routingHintFallbackSetIDs != null) 882 { 883 buffer.append(", fallbackSetIDs={"); 884 iterator = routingHintFallbackSetIDs.iterator(); 885 while (iterator.hasNext()) 886 { 887 buffer.append('\''); 888 buffer.append(iterator.next()); 889 buffer.append('\''); 890 891 if (iterator.hasNext()) 892 { 893 buffer.append(", "); 894 } 895 } 896 buffer.append('}'); 897 } 898 break; 899 } 900 buffer.append(')'); 901 } 902}