001/*
002 * Copyright 2012-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2019 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.extensions;
022
023
024
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.Collections;
028import java.util.Iterator;
029import java.util.List;
030
031import com.unboundid.asn1.ASN1Element;
032import com.unboundid.asn1.ASN1OctetString;
033import com.unboundid.asn1.ASN1Sequence;
034import com.unboundid.ldap.sdk.Control;
035import com.unboundid.ldap.sdk.ExtendedResult;
036import com.unboundid.ldap.sdk.LDAPException;
037import com.unboundid.ldap.sdk.ResultCode;
038import com.unboundid.util.Debug;
039import com.unboundid.util.NotMutable;
040import com.unboundid.util.StaticUtils;
041import com.unboundid.util.ThreadSafety;
042import com.unboundid.util.ThreadSafetyLevel;
043
044import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
045
046
047
048/**
049 * This class provides an implementation of an extended result that can be used
050 * to provide information about the notification subscriptions defined in the
051 * target server.
052 * <BR>
053 * <BLOCKQUOTE>
054 *   <B>NOTE:</B>  This class, and other classes within the
055 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
056 *   supported for use against Ping Identity, UnboundID, and
057 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
058 *   for proprietary functionality or for external specifications that are not
059 *   considered stable or mature enough to be guaranteed to work in an
060 *   interoperable way with other types of LDAP servers.
061 * </BLOCKQUOTE>
062 * <BR>
063 * The OID for this result is 1.3.6.1.4.1.30221.2.6.41, and the value (if
064 * present) should have the following encoding:
065 * <BR><BR>
066 * <PRE>
067 *   ListNotificationSubscriptionsResponse ::= SEQUENCE OF SEQUENCE {
068 *        notificationDestinationID     OCTET STRING,
069 *        destinationDetails            SEQUENCE OF OCTET STRING,
070 *        subscriptions                 SEQUENCE OF SEQUENCE {
071 *             subscriptionID          OCTET STRING,
072 *             subscriptionDetails     SEQUENCE OF OCTET STRING } }
073 * </PRE>
074 */
075@NotMutable()
076@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
077public final class ListNotificationSubscriptionsExtendedResult
078       extends ExtendedResult
079{
080  /**
081   * The OID (1.3.6.1.4.1.30221.2.6.41) for the list notification subscriptions
082   * extended result.
083   */
084  public static final String LIST_NOTIFICATION_SUBSCRIPTIONS_RESULT_OID =
085       "1.3.6.1.4.1.30221.2.6.41";
086
087
088
089  /**
090   * The serial version UID for this serializable class.
091   */
092  private static final long serialVersionUID = 8876370324325619149L;
093
094
095
096  // The notification destination details for this result.
097  private final List<NotificationDestinationDetails> destinations;
098
099
100
101  /**
102   * Creates a new list notification subscriptions extended result from the
103   * provided extended result.
104   *
105   * @param  extendedResult  The extended result to be decoded as a list
106   *                         notification subscriptions extended result.
107   *
108   * @throws LDAPException  If a problem is encountered while attempting to
109   *                         decode the provided extended result as a
110   *                         multi-update result.
111   */
112  public ListNotificationSubscriptionsExtendedResult(
113              final ExtendedResult extendedResult)
114         throws LDAPException
115  {
116    super(extendedResult);
117
118    final ASN1OctetString value = extendedResult.getValue();
119    if (value == null)
120    {
121      destinations = Collections.emptyList();
122      return;
123    }
124
125    try
126    {
127      final ASN1Element[] destsElements =
128           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
129      final ArrayList<NotificationDestinationDetails> destList =
130           new ArrayList<>(destsElements.length);
131      for (final ASN1Element destElement : destsElements)
132      {
133        final ASN1Element[] destElements =
134             ASN1Sequence.decodeAsSequence(destElement).elements();
135        final String destID =
136             ASN1OctetString.decodeAsOctetString(destElements[0]).stringValue();
137
138        final ASN1Element[] destDetailsElements =
139             ASN1Sequence.decodeAsSequence(destElements[1]).elements();
140        final ArrayList<ASN1OctetString> destDetailsList =
141             new ArrayList<>(destDetailsElements.length);
142        for (final ASN1Element e : destDetailsElements)
143        {
144          destDetailsList.add(ASN1OctetString.decodeAsOctetString(e));
145        }
146
147        final ASN1Element[] subElements =
148             ASN1Sequence.decodeAsSequence(destElements[2]).elements();
149        final ArrayList<NotificationSubscriptionDetails> subscriptions =
150             new ArrayList<>(subElements.length);
151        for (final ASN1Element e : subElements)
152        {
153          final ASN1Element[] sElements =
154               ASN1Sequence.decodeAsSequence(e).elements();
155          final String subID =
156               ASN1OctetString.decodeAsOctetString(sElements[0]).stringValue();
157
158          final ASN1Element[] subDetailsElements =
159               ASN1Sequence.decodeAsSequence(sElements[1]).elements();
160          final ArrayList<ASN1OctetString> subDetails =
161               new ArrayList<>(subDetailsElements.length);
162          for (final ASN1Element sde : subDetailsElements)
163          {
164            subDetails.add(ASN1OctetString.decodeAsOctetString(sde));
165          }
166          subscriptions.add(
167               new NotificationSubscriptionDetails(subID, subDetails));
168        }
169
170        destList.add(new NotificationDestinationDetails(destID, destDetailsList,
171             subscriptions));
172      }
173
174      destinations = Collections.unmodifiableList(destList);
175    }
176    catch (final Exception e)
177    {
178      Debug.debugException(e);
179      throw new LDAPException(ResultCode.DECODING_ERROR,
180           ERR_LIST_NOTIFICATION_SUBS_RESULT_CANNOT_DECODE_VALUE.get(
181                StaticUtils.getExceptionMessage(e)),
182           e);
183    }
184  }
185
186
187
188  /**
189   * Creates a new list notification subscriptions extended request with the
190   * provided information.
191   *
192   * @param  messageID          The message ID for this extended result.
193   * @param  resultCode         The result code for this result.  It must not be
194   *                            {@code null}.
195   * @param  diagnosticMessage  The diagnostic message to include in the result.
196   *                            It may be {@code null} if no diagnostic message
197   *                            should be included.
198   * @param  matchedDN          The matched DN to include in the result.  It may
199   *                            be {@code null} if no matched DN should be
200   *                            included.
201   * @param  referralURLs       The set of referral URLs to include in the
202   *                            result.  It may be {@code null} or empty if no
203   *                            referral URLs should be included.
204   * @param  destinations       The notification destination details for this
205   *                            result.  It may be {@code null} or empty for a
206   *                            non-success result.
207   * @param  controls           The set of controls to include in the
208   *                            multi-update result.  It may be {@code null} or
209   *                            empty if no controls should be included.
210   *
211   * @throws  LDAPException  If any of the results are for an inappropriate
212   *                         operation type.
213   */
214  public ListNotificationSubscriptionsExtendedResult(final int messageID,
215              final ResultCode resultCode, final String diagnosticMessage,
216              final String matchedDN, final String[] referralURLs,
217              final Collection<NotificationDestinationDetails> destinations,
218              final Control... controls)
219         throws LDAPException
220  {
221    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
222         LIST_NOTIFICATION_SUBSCRIPTIONS_RESULT_OID, encodeValue(destinations),
223         controls);
224
225    if (destinations == null)
226    {
227      this.destinations = Collections.emptyList();
228    }
229    else
230    {
231      this.destinations =
232           Collections.unmodifiableList(new ArrayList<>(destinations));
233    }
234  }
235
236
237
238  /**
239   * Encodes the information from the provided set of results into a form
240   * suitable for use as the value of the extended result.
241   *
242   * @param  destinations  The notification destination details for the result.
243   *                       It may be {@code null} or empty for a non-success
244   *                       result.
245   *
246   * @return  An ASN.1 element suitable for use as the value of the extended
247   *          result.
248   */
249  private static ASN1OctetString encodeValue(
250               final Collection<NotificationDestinationDetails> destinations)
251  {
252    if ((destinations == null) || destinations.isEmpty())
253    {
254      return null;
255    }
256
257    final ArrayList<ASN1Element> elements =
258         new ArrayList<>(destinations.size());
259    for (final NotificationDestinationDetails destDetails : destinations)
260    {
261      final ArrayList<ASN1Element> destElements = new ArrayList<>(3);
262      destElements.add(new ASN1OctetString(destDetails.getID()));
263      destElements.add(new ASN1Sequence(destDetails.getDetails()));
264
265      final ArrayList<ASN1Element> subElements =
266           new ArrayList<>(destDetails.getSubscriptions().size());
267      for (final NotificationSubscriptionDetails subDetails :
268           destDetails.getSubscriptions())
269      {
270        subElements.add(new ASN1Sequence(
271             new ASN1OctetString(subDetails.getID()),
272             new ASN1Sequence(subDetails.getDetails())));
273      }
274      destElements.add(new ASN1Sequence(subElements));
275      elements.add(new ASN1Sequence(destElements));
276    }
277
278    return new ASN1OctetString(new ASN1Sequence(elements).encode());
279  }
280
281
282
283  /**
284   * Retrieves a list of the defined notification destinations and their
285   * associated subscriptions.
286   *
287   * @return  A list of the defined notification destinations and their
288   *          associated subscriptions.
289   */
290  public List<NotificationDestinationDetails> getDestinations()
291  {
292    return destinations;
293  }
294
295
296
297  /**
298   * {@inheritDoc}
299   */
300  @Override()
301  public String getExtendedResultName()
302  {
303    return INFO_EXTENDED_RESULT_NAME_LIST_NOTIFICATION_SUBS.get();
304  }
305
306
307
308  /**
309   * Appends a string representation of this extended result to the provided
310   * buffer.
311   *
312   * @param  buffer  The buffer to which a string representation of this
313   *                 extended result will be appended.
314   */
315  @Override()
316  public void toString(final StringBuilder buffer)
317  {
318    buffer.append("ListNotificationSubscriptionsExtendedResult(resultCode=");
319    buffer.append(getResultCode());
320
321    final int messageID = getMessageID();
322    if (messageID >= 0)
323    {
324      buffer.append(", messageID=");
325      buffer.append(messageID);
326    }
327
328    buffer.append(", notificationDestinations={");
329    final Iterator<NotificationDestinationDetails> destIterator =
330         destinations.iterator();
331    while (destIterator.hasNext())
332    {
333      destIterator.next().toString(buffer);
334      if (destIterator.hasNext())
335      {
336        buffer.append(", ");
337      }
338    }
339    buffer.append('}');
340
341    final String diagnosticMessage = getDiagnosticMessage();
342    if (diagnosticMessage != null)
343    {
344      buffer.append(", diagnosticMessage='");
345      buffer.append(diagnosticMessage);
346      buffer.append('\'');
347    }
348
349    final String matchedDN = getMatchedDN();
350    if (matchedDN != null)
351    {
352      buffer.append(", matchedDN='");
353      buffer.append(matchedDN);
354      buffer.append('\'');
355    }
356
357    final String[] referralURLs = getReferralURLs();
358    if (referralURLs.length > 0)
359    {
360      buffer.append(", referralURLs={");
361      for (int i=0; i < referralURLs.length; i++)
362      {
363        if (i > 0)
364        {
365          buffer.append(", ");
366        }
367
368        buffer.append('\'');
369        buffer.append(referralURLs[i]);
370        buffer.append('\'');
371      }
372      buffer.append('}');
373    }
374
375    final Control[] responseControls = getResponseControls();
376    if (responseControls.length > 0)
377    {
378      buffer.append(", responseControls={");
379      for (int i=0; i < responseControls.length; i++)
380      {
381        if (i > 0)
382        {
383          buffer.append(", ");
384        }
385
386        buffer.append(responseControls[i]);
387      }
388      buffer.append('}');
389    }
390
391    buffer.append(')');
392  }
393}