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