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 }