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