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