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.List;
032import java.util.Set;
033
034import com.unboundid.asn1.ASN1Element;
035import com.unboundid.asn1.ASN1OctetString;
036import com.unboundid.asn1.ASN1Sequence;
037import com.unboundid.asn1.ASN1Set;
038import com.unboundid.ldap.sdk.Control;
039import com.unboundid.ldap.sdk.DecodeableControl;
040import com.unboundid.ldap.sdk.ExtendedResult;
041import com.unboundid.ldap.sdk.LDAPException;
042import com.unboundid.ldap.sdk.LDAPResult;
043import com.unboundid.ldap.sdk.ResultCode;
044import com.unboundid.ldap.sdk.SearchResultEntry;
045import com.unboundid.util.Debug;
046import com.unboundid.util.NotMutable;
047import com.unboundid.util.StaticUtils;
048import com.unboundid.util.ThreadSafety;
049import com.unboundid.util.ThreadSafetyLevel;
050import com.unboundid.util.Validator;
051
052import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
053
054
055
056/**
057 * This class provides a response control that may be used to provide the
058 * backend set ID(s) for any relevant backend sets accessed during the course
059 * of processing an operation.  It may be returned in response to a request
060 * containing either the get backend set ID request control or the route to
061 * backend set request control.  For add, simple bind, compare, delete,
062 * modify, and modify DN operations, the LDAP result message for the operation
063 * may contain zero or one get backend set ID response control.  For extended
064 * operations, the extended result message may contain zero, one, or multiple
065 * get backend set ID response controls.  For search operations, each search
066 * result entry may contain zero or one get backend set ID response control,
067 * while the search result done message will not contain any such control.  See
068 * the {@link GetBackendSetIDRequestControl} class documentation for a more
069 * complete description of the usage for these controls.
070 * <BR>
071 * <BLOCKQUOTE>
072 *   <B>NOTE:</B>  This class, and other classes within the
073 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
074 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
075 *   server products.  These classes provide support for proprietary
076 *   functionality or for external specifications that are not considered stable
077 *   or mature enough to be guaranteed to work in an interoperable way with
078 *   other types of LDAP servers.
079 * </BLOCKQUOTE>
080 * <BR>
081 * The get backend set ID response control has an OID of
082 * "1.3.6.1.4.1.30221.2.5.34", a criticality of false, and a value with the
083 * following encoding:
084 * <PRE>
085 *   GET_BACKEND_SET_ID_RESPONSE_VALUE ::= SEQUENCE {
086 *     entryBalancingRequestProcessorID     OCTET STRING,
087 *     backendSetIDs                        SET SIZE (1..MAX) OF OCTET STRING,
088 *     ... }
089 * </PRE>
090 *
091 * @see  GetBackendSetIDRequestControl
092 * @see  RouteToBackendSetRequestControl
093 */
094@NotMutable()
095@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
096public final class GetBackendSetIDResponseControl
097       extends Control
098       implements DecodeableControl
099{
100  /**
101   * The OID (1.3.6.1.4.1.30221.2.5.34) for the get backend set ID response
102   * control.
103   */
104  public static final  String GET_BACKEND_SET_ID_RESPONSE_OID =
105       "1.3.6.1.4.1.30221.2.5.34";
106
107
108
109  /**
110   * The serial version UID for this serializable class.
111   */
112  private static final long serialVersionUID = 117359364981309726L;
113
114
115
116  // The backend set IDs for backend sets used during processing.
117  private final Set<String> backendSetIDs;
118
119  // The identifier for the entry-balancing request processor with which the
120  // backend set IDs are associated.
121  private final String entryBalancingRequestProcessorID;
122
123
124
125  /**
126   * Creates a new empty control instance that is intended to be used only for
127   * decoding controls via the {@code DecodeableControl} interface.
128   */
129  GetBackendSetIDResponseControl()
130  {
131    entryBalancingRequestProcessorID = null;
132    backendSetIDs = null;
133  }
134
135
136
137  /**
138   * Creates a new get backend set ID response control with the provided
139   * information.
140   *
141   * @param  entryBalancingRequestProcessorID  The identifier for the
142   *                                           entry-balancing request processor
143   *                                           with which the backend set IDs
144   *                                           are associated.  It must not be
145   *                                           {@code null}.
146   * @param  backendSetID                      The backend set ID for the
147   *                                           backend set used during
148   *                                           processing.  It must not be
149   *                                           {@code null}.
150   */
151  public GetBackendSetIDResponseControl(
152              final String entryBalancingRequestProcessorID,
153              final String backendSetID)
154  {
155    this(entryBalancingRequestProcessorID, Arrays.asList(backendSetID));
156  }
157
158
159
160  /**
161   * Creates a new get backend set ID response control with the provided
162   * information.
163   *
164   * @param  entryBalancingRequestProcessorID  The identifier for the
165   *                                           entry-balancing request processor
166   *                                           with which the backend set IDs
167   *                                           are associated.  It must not be
168   *                                           {@code null}.
169   * @param  backendSetIDs                     The backend set IDs for backend
170   *                                           sets used during processing.  It
171   *                                           must not be {@code null} or
172   *                                           empty.
173   */
174  public GetBackendSetIDResponseControl(
175              final String entryBalancingRequestProcessorID,
176              final Collection<String> backendSetIDs)
177  {
178    super(GET_BACKEND_SET_ID_RESPONSE_OID, false,
179         encodeValue(entryBalancingRequestProcessorID, backendSetIDs));
180
181    this.entryBalancingRequestProcessorID = entryBalancingRequestProcessorID;
182    this.backendSetIDs =
183         Collections.unmodifiableSet(new LinkedHashSet<String>(backendSetIDs));
184  }
185
186
187
188  /**
189   * Creates a new get backend set ID response control decoded from the given
190   * generic control contents.
191   *
192   * @param  oid         The OID for the control.
193   * @param  isCritical  Indicates whether this control should be marked
194   *                     critical.
195   * @param  value       The encoded value for the control.
196   *
197   * @throws LDAPException  If a problem occurs while attempting to decode the
198   *                        generic control as a get backend set ID response
199   *                        control.
200   */
201  public GetBackendSetIDResponseControl(final String oid,
202                                        final boolean isCritical,
203                                        final ASN1OctetString value)
204       throws LDAPException
205  {
206    super(oid, isCritical, value);
207
208    if (value == null)
209    {
210      throw new LDAPException(ResultCode.DECODING_ERROR,
211           ERR_GET_BACKEND_SET_ID_RESPONSE_MISSING_VALUE.get());
212    }
213
214    try
215    {
216      final ASN1Element[] elements =
217           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
218      entryBalancingRequestProcessorID =
219           ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
220
221      final ASN1Element[] backendSetIDElements =
222           ASN1Set.decodeAsSet(elements[1]).elements();
223      final LinkedHashSet<String> setIDs =
224           new LinkedHashSet<String>(backendSetIDElements.length);
225      for (final ASN1Element e : backendSetIDElements)
226      {
227        setIDs.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
228      }
229      backendSetIDs = Collections.unmodifiableSet(setIDs);
230    }
231    catch (final Exception e)
232    {
233      Debug.debugException(e);
234      throw new LDAPException(ResultCode.DECODING_ERROR,
235           ERR_GET_BACKEND_SET_ID_RESPONSE_CANNOT_DECODE.get(
236                StaticUtils.getExceptionMessage(e)),
237           e);
238    }
239  }
240
241
242
243  /**
244   * Encodes the provided information into an octet string suitable for use as
245   * the value of this control.
246   *
247   * @param  entryBalancingRequestProcessorID  The identifier for the
248   *                                           entry-balancing request processor
249   *                                           with which the backend set IDs
250   *                                           are associated.  It must not be
251   *                                           {@code null}.
252   * @param  backendSetIDs                     The backend set IDs for backend
253   *                                           sets used during processing.  It
254   *                                           must not be {@code null} or
255   *                                           empty.
256   *
257   * @return  The encoded representation of the control value.
258   */
259  private static ASN1OctetString encodeValue(
260                      final String entryBalancingRequestProcessorID,
261                      final Collection<String> backendSetIDs)
262  {
263    Validator.ensureNotNull(entryBalancingRequestProcessorID);
264    Validator.ensureNotNull(backendSetIDs);
265    Validator.ensureFalse(backendSetIDs.isEmpty());
266
267    final ArrayList<ASN1Element> backendSetIDElements =
268         new ArrayList<ASN1Element>(backendSetIDs.size());
269    for (final String s : backendSetIDs)
270    {
271      backendSetIDElements.add(new ASN1OctetString(s));
272    }
273
274    final ASN1Sequence valueSequence = new ASN1Sequence(
275         new ASN1OctetString(entryBalancingRequestProcessorID),
276         new ASN1Set(backendSetIDElements));
277    return new ASN1OctetString(valueSequence.encode());
278  }
279
280
281
282  /**
283   * {@inheritDoc}
284   */
285  @Override()
286  public GetBackendSetIDResponseControl decodeControl(final String oid,
287                                             final boolean isCritical,
288                                             final ASN1OctetString value)
289         throws LDAPException
290  {
291    return new GetBackendSetIDResponseControl(oid, isCritical, value);
292  }
293
294
295
296  /**
297   * Retrieves the identifier for the entry-balancing request processor with
298   * which the backend sets IDs are associated.
299   *
300   * @return  The identifier for the entry-balancing request processor with
301   *          which the backend set IDs are associated.
302   */
303  public String getEntryBalancingRequestProcessorID()
304  {
305    return entryBalancingRequestProcessorID;
306  }
307
308
309
310  /**
311   * Retrieves the backend set IDs for the backend sets used during processing.
312   *
313   * @return  The backend set IDs for the backend sets used during processing.
314   */
315  public Set<String> getBackendSetIDs()
316  {
317    return backendSetIDs;
318  }
319
320
321
322  /**
323   * Extracts a get backend set ID response control from the provided result.
324   *
325   * @param  result  The result from which to retrieve the get backend set ID
326   *                 response control.
327   *
328   * @return  The get backend set ID response control contained in the provided
329   *          result, or {@code null} if the result did not contain a get
330   *          backend set ID response control.
331   *
332   * @throws  LDAPException  If a problem is encountered while attempting to
333   *                         decode the get backend set ID response control
334   *                         contained in the provided result.
335   */
336  public static GetBackendSetIDResponseControl get(final LDAPResult result)
337         throws LDAPException
338  {
339    final Control c =
340         result.getResponseControl(GET_BACKEND_SET_ID_RESPONSE_OID);
341    if (c == null)
342    {
343      return null;
344    }
345
346    if (c instanceof GetBackendSetIDResponseControl)
347    {
348      return (GetBackendSetIDResponseControl) c;
349    }
350    else
351    {
352      return new GetBackendSetIDResponseControl(c.getOID(), c.isCritical(),
353           c.getValue());
354    }
355  }
356
357
358
359  /**
360   * Extracts a get backend set ID response control from the provided search
361   * result entry.
362   *
363   * @param  entry  The entry from which to retrieve the get backend set ID
364   *                response control.
365   *
366   * @return  The get backend set ID response control contained in the provided
367   *          entry, or {@code null} if the entry did not contain a get backend
368   *          set ID response control.
369   *
370   * @throws  LDAPException  If a problem is encountered while attempting to
371   *                         decode the get backend set ID response control
372   *                         contained in the provided result.
373   */
374  public static GetBackendSetIDResponseControl
375                     get(final SearchResultEntry entry)
376         throws LDAPException
377  {
378    final Control c = entry.getControl(GET_BACKEND_SET_ID_RESPONSE_OID);
379    if (c == null)
380    {
381      return null;
382    }
383
384    if (c instanceof GetBackendSetIDResponseControl)
385    {
386      return (GetBackendSetIDResponseControl) c;
387    }
388    else
389    {
390      return new GetBackendSetIDResponseControl(c.getOID(), c.isCritical(),
391           c.getValue());
392    }
393  }
394
395
396
397  /**
398   * Extracts any get backend set ID response controls from the provided
399   * extended result.
400   *
401   * @param  result  The extended result from which to retrieve the get backend
402   *                 set ID response control(s).
403   *
404   * @return  A list of get backend set ID response controls contained in the
405   *          provided extended result, or an empty list if the result did not
406   *          contain a get any backend set ID response controls.
407   *
408   * @throws  LDAPException  If a problem is encountered while attempting to
409   *                         decode the any backend set ID response control
410   *                         contained in the provided result.
411   */
412  public static List<GetBackendSetIDResponseControl>
413                     get(final ExtendedResult result)
414         throws LDAPException
415  {
416    final Control[] controls = result.getResponseControls();
417    if (controls.length == 0)
418    {
419      return Collections.emptyList();
420    }
421
422    final ArrayList<GetBackendSetIDResponseControl> decodedControls =
423         new ArrayList<GetBackendSetIDResponseControl>(controls.length);
424    for (final Control c : controls)
425    {
426      if (c instanceof GetBackendSetIDResponseControl)
427      {
428        decodedControls.add((GetBackendSetIDResponseControl) c);
429      }
430      else if (c.getOID().equals(GET_BACKEND_SET_ID_RESPONSE_OID))
431      {
432        decodedControls.add(new GetBackendSetIDResponseControl(c.getOID(),
433             c.isCritical(), c.getValue()));
434      }
435    }
436
437    return Collections.unmodifiableList(decodedControls);
438  }
439
440
441
442  /**
443   * {@inheritDoc}
444   */
445  @Override()
446  public String getControlName()
447  {
448    return INFO_CONTROL_NAME_GET_BACKEND_SET_ID_RESPONSE.get();
449  }
450
451
452
453  /**
454   * {@inheritDoc}
455   */
456  @Override()
457  public void toString(final StringBuilder buffer)
458  {
459    buffer.append("GetBackendSetIDResponseControl(" +
460         "entryBalancingRequestProcessorID='");
461    buffer.append(entryBalancingRequestProcessorID);
462    buffer.append("', backendSetIDs={");
463
464    final Iterator<String> iterator = backendSetIDs.iterator();
465    while (iterator.hasNext())
466    {
467      buffer.append('\'');
468      buffer.append(iterator.next());
469      buffer.append('\'');
470
471      if (iterator.hasNext())
472      {
473        buffer.append(", ");
474      }
475    }
476
477    buffer.append("})");
478  }
479}