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.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.LinkedHashSet; 031import java.util.Set; 032 033import com.unboundid.asn1.ASN1Element; 034import com.unboundid.asn1.ASN1OctetString; 035import com.unboundid.asn1.ASN1Sequence; 036import com.unboundid.asn1.ASN1Set; 037import com.unboundid.ldap.sdk.Control; 038import com.unboundid.ldap.sdk.LDAPException; 039import com.unboundid.ldap.sdk.ResultCode; 040import com.unboundid.util.Debug; 041import com.unboundid.util.NotMutable; 042import com.unboundid.util.StaticUtils; 043import com.unboundid.util.ThreadSafety; 044import com.unboundid.util.ThreadSafetyLevel; 045import com.unboundid.util.Validator; 046 047import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*; 048 049 050 051/** 052 * This class provides a request control which may be used to request that the 053 * Directory Proxy Server forward the associated operation to a specific backend 054 * set associated with an entry-balancing request processor. It may be either 055 * an absolute routing request, indicating that the target backend set(s) are 056 * the only ones that may be used to process the operation, or it may be used to 057 * provide a routing hint in lieu of accessing the global index. 058 * <BR> 059 * <BLOCKQUOTE> 060 * <B>NOTE:</B> This class, and other classes within the 061 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 062 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 063 * server products. These classes provide support for proprietary 064 * functionality or for external specifications that are not considered stable 065 * or mature enough to be guaranteed to work in an interoperable way with 066 * other types of LDAP servers. 067 * </BLOCKQUOTE> 068 * <BR> 069 * This control may be used for a number of different kinds of requests, as 070 * follows: 071 * <UL> 072 * <LI>For an add request that uses absolute routing, exactly one target 073 * backend set ID must be specified, and the request will be sent only to 074 * that backend set. 075 * <BR> 076 * <B>WARNING</B>: The use of absolute routing for an add 077 * operation bypasses the check to ensure that no entry already exists 078 * with the same DN as the new entry, so it is possible that an add 079 * performed immediately below the balancing point could result in 080 * creating an entry in one backend set with the same DN as another entry 081 * in a different backend set. Similarly, if the entry-balancing request 082 * processor is configured to broadcast add operations outside the 083 * balancing point rather than relying on those adds to be replicated, 084 * then it is strongly recommended that absolute routing not be used for 085 * add operations outside the balancing point because that will cause the 086 * entry to be added to only one backend set rather than to all backend 087 * sets.</LI> 088 * <LI>For an add request that uses a routing hint, exactly one target backend 089 * set ID must be specified for the first guess, although any number of 090 * fallback set IDs may be specified. For entries immediately below the 091 * balancing point, the routing hint will be used instead of a placement 092 * algorithm in order to select which backend set should hold the entry 093 * (and the fallback sets will not be used). For entries more than one 094 * level below the balancing point, the routing hint will be used in lieu 095 * of the global index as an attempt to determine where the parent entry 096 * exists, and the fallback sets may be used if the parent entry doesn't 097 * exist in the first guess set. For entries outside the balancing point, 098 * if the entry-balancing request processor is configured to add entries 099 * to one set and allow them to be replicated to other sets, then the 100 * first guess hint will be used to select the set to which the entry will 101 * be added (and the fallback sets will not be used). An add operation 102 * with a routing hint cannot be used to create multiple entries with the 103 * same DN in different backend sets, nor can it cause an entry outside 104 * the balancing point to exist in only one backend set.</LI> 105 * <LI>For a simple bind request that uses absolute routing, exactly one 106 * target backend set ID must be specified, and the request will be sent 107 * only to that backend set. If the bind fails in that set, even if the 108 * failure is because the target entry does not exist in that backend set, 109 * then the failure will be returned to the client rather than attempting 110 * the operation in a different backend set.</LI> 111 * <LI>For a simple bind request that uses a routing hint, exactly one target 112 * backend set ID must be specified for the first guess, although any 113 * number of fallback set IDs may be specified. If the bind fails in the 114 * first guess set, it may be re-attempted in the fallback sets.</LI> 115 * <LI>For a compare request that uses absolute routing, exactly one target 116 * backend set ID must be specified, and the request will be sent only to 117 * that backend set. If the compare fails in that set, even if the 118 * failure is because the target entry does not exist in that set, then 119 * the failure will be returned to the client rather than attempting the 120 * operation in a different backend set.</LI> 121 * <LI>For a compare request that uses a routing hint, exactly one target 122 * backend set ID must be specified for the first guess, although any 123 * number of fallback set IDs may be specified. If the compare operation 124 * fails in the first guess set in a way that suggests the target entry 125 * does not exist in that backend set, then it will be re-attempted in the 126 * fallback sets.</LI> 127 * <LI>For a delete request that uses absolute routing, exactly one target 128 * backend set ID must be specified, and the request will be sent only to 129 * that backend set. If the delete fails in that set, even if the failure 130 * is because the target entry does not exist in that set, then the 131 * failure will be returned to the client rather than attempting the 132 * operation in a different backend set. 133 * <BR> 134 * <B>WARNING</B>: If the entry-balancing request processor is configured 135 * to broadcast delete operations outside the balancing point rather than 136 * relying on those deletes to be replicated, then it is strongly 137 * recommended that absolute routing not be used for delete operations 138 * outside the balancing point because that will cause the entry to be 139 * deleted in only one backend set and will remain in all other backend 140 * sets.</LI> 141 * <LI>For a delete request that uses a routing hint, exactly one target 142 * backend set ID must be specified for the first guess, although any 143 * number of fallback set IDs may be specified. For entries below the 144 * balancing point, the routing hint will be used in lieu of the global 145 * index in order to determine which backend set contains the target 146 * entry. If the delete fails in the first guess set in a way that 147 * suggests that the target entry does not exist in that backend set, then 148 * it will be re-attempted in the fallback sets. 149 * <BR> 150 * For entries outside the balancing point, if the entry-balancing request 151 * processor is configured to delete entries from only one backend set 152 * and allow that delete to be replicated to all other sets, then the 153 * routing hint may be used to select the set from which that entry will 154 * be deleted. A delete operation with a routing hint cannot be used to 155 * cause an entry outside the balancing point to be removed from only one 156 * backend set while leaving it in the remaining sets.</LI> 157 * <LI>For an atomic multi-update extended request, only absolute routing is 158 * supported, and the route to backend set request control must be 159 * attached to the extended operation itself and not to any of the 160 * requests contained inside the multi-update. Exactly one backend set ID 161 * must be specified, and the multi-update request will be sent only to 162 * that backend set.</LI> 163 * <LI>For a non-atomic multi-update extended request, the extended operation 164 * must not include a route to backend set request control. However, any 165 * or all of the requests inside the multi-update request may include a 166 * route to backend set request control, and in that case it will be 167 * treated in the same way as for a request of the same type not 168 * included in multi-update request (e.g., if a multi-update extended 169 * operation includes an add request with a route to backend set request 170 * control, then that route control will have the same effect as for the 171 * same add request with the same control processed outside a multi-update 172 * operation).</LI> 173 * <LI>For an extended request that will be processed by a proxied extended 174 * operation handler, the request may include a route to backend set 175 * request control and that control will be used to select the target 176 * backend sets instead of the proxied extended operation handler's 177 * {@code selectBackendSets} method.</LI> 178 * <LI>For a modify request that uses absolute routing, exactly one target 179 * backend set ID must be specified, and the request will be sent only to 180 * that backend set. If the modify fails in that set, even if the failure 181 * is because the target entry does not exist in that set, then the 182 * failure will be returned to the client rather than attempting the 183 * operation in a different backend set. 184 * <BR> 185 * <B>WARNING</B>: When processing a modify operation against the 186 * balancing point entry itself, the Directory Proxy Server will typically 187 * send that modify request to all backend sets to ensure that it is 188 * properly applied everywhere. However, with an absolute routing 189 * request, the modify operation will be sent only to one backend set, 190 * which will cause the entry in that set to be out of sync with the entry 191 * in all other sets. It is therefore strongly recommended that absolute 192 * routing not be used for modify operations that target the balancing 193 * point entry. Similarly, if the entry-balancing request processor is 194 * configured to broadcast modify operations targeting entries outside the 195 * balancing point to all backend sets rather than having those modify 196 * operations replicated to the other backend sets, it is strongly 197 * recommended that absolute routing not be used for those operations 198 * because the request will be sent to only one set, causing the entry in 199 * that set to be out of sync with the corresponding entry in other 200 * backend sets.</LI> 201 * <LI>For a modify request that uses a routing hint, exactly one target 202 * backend set ID must be specified for the first guess, although any 203 * number of fallback set IDs may be specified. For entries below the 204 * balancing point, the routing hint will be used in lieu of the global 205 * index in order to determine which backend set contains the target 206 * entry. If the modify attempt fails in the first guess set in a way 207 * that suggests the target entry does not exist in that backend set, then 208 * it will be re-attempted in the fallback sets. 209 * <BR> 210 * For modify operations that target the balancing point entry itself, the 211 * entry-balancing request processor will send the request to all backend 212 * sets, and the routing hint will not be used. Similarly, for entries 213 * outside the balancing point, if the entry-balancing request processor 214 * is configured to modify entries in only one backend set and allow that 215 * modify operation to be replicated to all other sets, then the routing 216 * hint may be used to select the set in which that entry will be 217 * modified. A modify operation with a routing hint cannot be used to 218 * cause an entry at or outside the balancing point to be updated in only 219 * one backend set, leaving it out of sync with the corresponding entry in 220 * the remaining sets.</LI> 221 * <LI>For a modify DN request that uses absolute routing, exactly one target 222 * backend set ID must be specified, and the request wil be sent only to 223 * that backend set. If the modify DN operation fails in that set, even 224 * if the failure is because the target entry does not exist in that set, 225 * then the failure will be returned to the client rather than attempting 226 * the operation in a different backend set. 227 * <BR> 228 * <B>WARNING</B>: Processing a modify DN operation with absolute routing 229 * bypasses the check to ensure that the new DN for the target entry does 230 * not conflict with the DN for an entry that exists in any other backend 231 * set. As a result, you are strongly discouraged from using absolute 232 * routing for any modify DN operation that would cause the new DN for the 233 * entry to be exactly one level below the balancing point. Further, for 234 * entries that exist outside the balancing point, if the entry-balancing 235 * request processor is configured to broadcast modify DN operations 236 * rather than expecting them to be replicated to the other backend sets, 237 * a modify DN operation with absolute routing would cause the change to 238 * be applied only in one backend set, leaving it out of sync with the 239 * other sets.</LI> 240 * <LI>For a modify DN request that uses a routing hint, exactly one target 241 * backend set ID must be specified for the first guess, although any 242 * number of fallback set IDs may be specified. For entries below the 243 * balancing point, the routing hint will be used in lieu of the global 244 * index in order to determine which backend set contains the target 245 * entry. If the modify attempt fails in the first guess set in a way 246 * that suggests the target entry does not exist in that backend set, then 247 * it will be re-attempted in the fallback sets. 248 * <BR> 249 * For entries outside the balancing point, if the entry-balancing request 250 * processor is configured to process modify DN operations in one backend 251 * set and allow them to be replicated to other backend sets, then the 252 * routing hint will be used to select which backend set should receive 253 * the modify DN request. A modify DN operation with a routing hint 254 * cannot be used to create a conflict in which the same DN exists in 255 * multiple backend sets, or a case in which a modify DN operation outside 256 * the balancing point leaves one backend set out of sync with the other 257 * sets.</LI> 258 * <LI>For a search request that uses absolute routing, there may be multiple 259 * target backend set IDs only if the scope of the search may include 260 * data from multiple backend sets (i.e., the base DN is at or above the 261 * balancing point, and the scope include entries at least one level below 262 * the balancing point entry). If the base and scope of the search allow 263 * it to match only entries at or above the balancing point or only 264 * entries within one backend set, then the absolute routing request must 265 * target exactly one backend set.</LI> 266 * <LI>For a search request that uses a routing hint, exactly one target 267 * backend set ID must be specified for the first guess, although any 268 * number of fallback set IDs may be specified. The routing hint will 269 * only be used for cases in which the entire scope of the search is 270 * contained entirely within a backend set (i.e., the entire scope is 271 * at or above the balancing point, or the entire scope is at least one 272 * level below the balancing point).</LI> 273 * </UL> 274 * <BR><BR> 275 * The OID for a route to backend set request control is 276 * "1.3.6.1.4.1.30221.2.5.35", and the criticality may be either {@code true} or 277 * {@code false}. It must have a value with the following encoding: 278 * <PRE> 279 * RouteToBackendSetRequest ::= SEQUENCE { 280 * entryBalancingRequestProcessorID OCTET STRING, 281 * backendSets CHOICE { 282 * absoluteRoutingRequest [0] SET OF OCTET STRING, 283 * routingHint [1] SEQUENCE { 284 * firstGuessSetIDs SET OF OCTET STRING, 285 * fallbackSetIDs SET OF OCTET STRING OPTIONAL } 286 * ... } 287 * ... } 288 * </PRE> 289 * The use of the route to backend set request control will also cause the 290 * server to behave as if the get backend set ID request control had been 291 * included, so that the get backend set ID response control may be included in 292 * operation result and search result entry messages as appropriate. 293 */ 294@NotMutable() 295@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 296public final class RouteToBackendSetRequestControl 297 extends Control 298{ 299 /** 300 * The OID (1.3.6.1.4.1.30221.2.5.35) for the route to server request control. 301 */ 302 public static final String ROUTE_TO_BACKEND_SET_REQUEST_OID = 303 "1.3.6.1.4.1.30221.2.5.35"; 304 305 306 307 /** 308 * The serial version UID for this serializable class. 309 */ 310 private static final long serialVersionUID = -2486448910813783450L; 311 312 313 314 // The routing type for the request. 315 private final RouteToBackendSetRoutingType routingType; 316 317 // The backend set IDs for an absolute routing request. 318 private final Set<String> absoluteBackendSetIDs; 319 320 // The backend set IDs for the fallback sets of a routing hint. 321 private final Set<String> routingHintFallbackSetIDs; 322 323 // The backend set IDs for the first guess of a routing hint. 324 private final Set<String> routingHintFirstGuessSetIDs; 325 326 // The identifier for the entry-balancing request processor with which the 327 // backend set IDs are associated. 328 private final String entryBalancingRequestProcessorID; 329 330 331 332 /** 333 * Creates a new route to backend set request control with the provided 334 * information. 335 * 336 * @param isCritical Indicates whether this control 337 * should be critical. 338 * @param encodedValue The encoded value for this 339 * control. It must not be 340 * {@code null}. 341 * @param entryBalancingRequestProcessorID The identifier for the 342 * entry-balancing request processor 343 * with which the backend set IDs 344 * are associated. It must not be 345 * {@code null}. 346 * @param routingType The routing type for this 347 * request. It must not be 348 * {@code null}. 349 * @param absoluteBackendSetIDs The collection of backend sets to 350 * which the request should be sent 351 * for an absolute routing request. 352 * It must be non-{@code null} and 353 * non-empty for an absolute routing 354 * request, and must be {@code null} 355 * for a routing hint. 356 * @param routingHintFirstGuessSetIDs The collection of backend sets 357 * that should be used as the first 358 * guess for a routing hint request. 359 * It must be {@code null} for an 360 * absolute routing request, and 361 * must be non-{@code null} and 362 * non-empty for a routing hint. 363 * @param routingHintFallbackSetIDs The collection of fallback 364 * backend sets that should be used 365 * for a routing hint request if the 366 * first guess was unsuccessful. It 367 * must be {@code null} for an 368 * absolute routing request, and may 369 * be {@code null} for a routing 370 * hint if the fallback sets should 371 * be all backend sets for the 372 * entry-balancing request processor 373 * that were not included in the 374 * first guess. If it is 375 * non-{@code null}, then it must 376 * also be non-empty. 377 */ 378 private RouteToBackendSetRequestControl(final boolean isCritical, 379 final ASN1OctetString encodedValue, 380 final String entryBalancingRequestProcessorID, 381 final RouteToBackendSetRoutingType routingType, 382 final Collection<String> absoluteBackendSetIDs, 383 final Collection<String> routingHintFirstGuessSetIDs, 384 final Collection<String> routingHintFallbackSetIDs) 385 { 386 super(ROUTE_TO_BACKEND_SET_REQUEST_OID, isCritical, encodedValue); 387 388 this.entryBalancingRequestProcessorID = entryBalancingRequestProcessorID; 389 this.routingType = routingType; 390 391 if (absoluteBackendSetIDs == null) 392 { 393 this.absoluteBackendSetIDs = null; 394 } 395 else 396 { 397 this.absoluteBackendSetIDs = Collections.unmodifiableSet( 398 new LinkedHashSet<String>(absoluteBackendSetIDs)); 399 } 400 401 if (routingHintFirstGuessSetIDs == null) 402 { 403 this.routingHintFirstGuessSetIDs = null; 404 } 405 else 406 { 407 this.routingHintFirstGuessSetIDs = Collections.unmodifiableSet( 408 new LinkedHashSet<String>(routingHintFirstGuessSetIDs)); 409 } 410 411 if (routingHintFallbackSetIDs == null) 412 { 413 this.routingHintFallbackSetIDs = null; 414 } 415 else 416 { 417 this.routingHintFallbackSetIDs = Collections.unmodifiableSet( 418 new LinkedHashSet<String>(routingHintFallbackSetIDs)); 419 } 420 } 421 422 423 424 /** 425 * Creates a new route to backend set request control that is decoded from the 426 * provided generic control. 427 * 428 * @param control The control to decode as a route to backend set request 429 * control. 430 * 431 * @throws LDAPException If the provided control cannot be decoded as a 432 * route to backend set request control. 433 */ 434 public RouteToBackendSetRequestControl(final Control control) 435 throws LDAPException 436 { 437 super(control); 438 439 final ASN1OctetString value = control.getValue(); 440 if (value == null) 441 { 442 throw new LDAPException(ResultCode.DECODING_ERROR, 443 ERR_ROUTE_TO_BACKEND_SET_REQUEST_MISSING_VALUE.get()); 444 } 445 446 try 447 { 448 final ASN1Element[] elements = 449 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 450 entryBalancingRequestProcessorID = 451 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 452 453 routingType = RouteToBackendSetRoutingType.valueOf(elements[1].getType()); 454 if (routingType == null) 455 { 456 throw new LDAPException(ResultCode.DECODING_ERROR, 457 ERR_ROUTE_TO_BACKEND_SET_REQUEST_UNKNOWN_ROUTING_TYPE.get( 458 StaticUtils.toHex(elements[1].getType()))); 459 } 460 461 if (routingType == RouteToBackendSetRoutingType.ABSOLUTE_ROUTING) 462 { 463 final ASN1Element[] arElements = 464 ASN1Set.decodeAsSet(elements[1]).elements(); 465 final LinkedHashSet<String> arSet = 466 new LinkedHashSet<String>(arElements.length); 467 for (final ASN1Element e : arElements) 468 { 469 arSet.add(ASN1OctetString.decodeAsOctetString(e).stringValue()); 470 } 471 absoluteBackendSetIDs = Collections.unmodifiableSet(arSet); 472 if (absoluteBackendSetIDs.isEmpty()) 473 { 474 throw new LDAPException(ResultCode.DECODING_ERROR, 475 ERR_ROUTE_TO_BACKEND_SET_REQUEST_ABSOLUTE_SET_EMPTY.get()); 476 } 477 478 routingHintFirstGuessSetIDs = null; 479 routingHintFallbackSetIDs = null; 480 } 481 else 482 { 483 final ASN1Element[] hintElements = 484 ASN1Sequence.decodeAsSequence(elements[1]).elements(); 485 486 final ASN1Element[] firstGuessElements = 487 ASN1Set.decodeAsSet(hintElements[0]).elements(); 488 final LinkedHashSet<String> firstGuessSet = 489 new LinkedHashSet<String>(firstGuessElements.length); 490 for (final ASN1Element e : firstGuessElements) 491 { 492 firstGuessSet.add( 493 ASN1OctetString.decodeAsOctetString(e).stringValue()); 494 } 495 routingHintFirstGuessSetIDs = 496 Collections.unmodifiableSet(firstGuessSet); 497 if (routingHintFirstGuessSetIDs.isEmpty()) 498 { 499 throw new LDAPException(ResultCode.DECODING_ERROR, 500 ERR_ROUTE_TO_BACKEND_SET_REQUEST_HINT_FIRST_SET_EMPTY.get()); 501 } 502 503 if (hintElements.length == 1) 504 { 505 routingHintFallbackSetIDs = null; 506 } 507 else 508 { 509 final ASN1Element[] fallbackElements = 510 ASN1Set.decodeAsSet(hintElements[1]).elements(); 511 final LinkedHashSet<String> fallbackSet = 512 new LinkedHashSet<String>(fallbackElements.length); 513 for (final ASN1Element e : fallbackElements) 514 { 515 fallbackSet.add( 516 ASN1OctetString.decodeAsOctetString(e).stringValue()); 517 } 518 routingHintFallbackSetIDs = Collections.unmodifiableSet(fallbackSet); 519 if (routingHintFallbackSetIDs.isEmpty()) 520 { 521 throw new LDAPException(ResultCode.DECODING_ERROR, 522 ERR_ROUTE_TO_BACKEND_SET_REQUEST_HINT_FALLBACK_SET_EMPTY. 523 get()); 524 } 525 } 526 527 absoluteBackendSetIDs = null; 528 } 529 } 530 catch (final LDAPException le) 531 { 532 Debug.debugException(le); 533 throw le; 534 } 535 catch (final Exception e) 536 { 537 Debug.debugException(e); 538 throw new LDAPException(ResultCode.DECODING_ERROR, 539 ERR_ROUTE_TO_BACKEND_SET_REQUEST_CANNOT_DECODE.get( 540 StaticUtils.getExceptionMessage(e)), 541 e); 542 } 543 } 544 545 546 547 /** 548 * Creates a new route to backend set request control that may be used for 549 * absolute routing to the specified backend set. 550 * 551 * @param isCritical Indicates whether the control 552 * should be marked critical. 553 * @param entryBalancingRequestProcessorID The identifier for the 554 * entry-balancing request processor 555 * with which the backend set ID 556 * is associated. It must not be 557 * {@code null}. 558 * @param backendSetID The backend set ID for the 559 * backend set to which the request 560 * should be forwarded. It must not 561 * be {@code null}. 562 * 563 * @return The route to backend set request control created from the 564 * provided information. 565 */ 566 public static RouteToBackendSetRequestControl createAbsoluteRoutingRequest( 567 final boolean isCritical, 568 final String entryBalancingRequestProcessorID, 569 final String backendSetID) 570 { 571 return createAbsoluteRoutingRequest(isCritical, 572 entryBalancingRequestProcessorID, Arrays.asList(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<ASN1Element>(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, Arrays.asList(firstGuessSetID), 662 fallbackSetIDs); 663 } 664 665 666 667 /** 668 * Creates a new route to backend set request control that may be used to 669 * provide a hint as to the backend set(s) to which the operation should be 670 * forwarded, and an optional specification of fallback sets. 671 * 672 * @param isCritical Indicates whether the control 673 * should be marked critical. 674 * @param entryBalancingRequestProcessorID The identifier for the 675 * entry-balancing request processor 676 * with which the backend set IDs 677 * are associated. It must not be 678 * {@code null}. 679 * @param firstGuessSetIDs The backend set ID(s) for the 680 * backend set(s) to try first. It 681 * must not be {@code null} or 682 * empty. 683 * @param fallbackSetIDs The backend set ID(s) for the 684 * backend set(s) to use if none of 685 * the servers in the first guess 686 * set returns a success result. 687 * If this is {@code null}, then the 688 * server will use a default 689 * fallback set of all backend sets 690 * not included in the first guess. 691 * If this is not {@code null}, then 692 * it must also be non-empty. 693 * 694 * @return The route to backend set request control created from the 695 * provided information. 696 */ 697 public static RouteToBackendSetRequestControl createRoutingHintRequest( 698 final boolean isCritical, 699 final String entryBalancingRequestProcessorID, 700 final Collection<String> firstGuessSetIDs, 701 final Collection<String> fallbackSetIDs) 702 { 703 Validator.ensureNotNull(firstGuessSetIDs); 704 Validator.ensureFalse(firstGuessSetIDs.isEmpty()); 705 706 if (fallbackSetIDs != null) 707 { 708 Validator.ensureFalse(fallbackSetIDs.isEmpty()); 709 } 710 711 final ArrayList<ASN1Element> backendSetsElements = 712 new ArrayList<ASN1Element>(2); 713 final ArrayList<ASN1Element> firstGuessElements = 714 new ArrayList<ASN1Element>(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<ASN1Element>(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}