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