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