001/*
002 * Copyright 2014-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2014-2022 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) 2014-2022 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.List;
044
045import com.unboundid.asn1.ASN1Element;
046import com.unboundid.asn1.ASN1Enumerated;
047import com.unboundid.asn1.ASN1OctetString;
048import com.unboundid.asn1.ASN1Sequence;
049import com.unboundid.ldap.sdk.Control;
050import com.unboundid.ldap.sdk.ExtendedRequest;
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;
060import com.unboundid.util.Validator;
061
062import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
063
064
065
066/**
067 * This class provides an extended request that may be used to create or update
068 * a notification destination.
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 request has an OID of 1.3.6.1.4.1.30221.2.6.36 and a value with the
081 * following encoding:
082 * <BR><BR>
083 * <PRE>
084 *   SetNotificationDestinationRequest ::= SEQUENCE {
085 *        notificationManagerID         OCTET STRING,
086 *        notificationDestinationID     OCTET STRING,
087 *        destinationDetails            SEQUENCE OF OCTET STRING,
088 *        changeType                    [0] ENUMERATED {
089 *             replace (0),
090 *             add (1),
091 *             delete (2) } DEFAULT replace }
092 * </PRE>
093 */
094@NotMutable()
095@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
096public final class SetNotificationDestinationExtendedRequest
097       extends ExtendedRequest
098{
099  /**
100   * The OID (1.3.6.1.4.1.30221.2.6.36) for the set notification destination
101   * extended request.
102   */
103  @NotNull public static final String SET_NOTIFICATION_DESTINATION_REQUEST_OID =
104       "1.3.6.1.4.1.30221.2.6.36";
105
106
107
108  /**
109   * The BER type for the value sequence element that specifies the destination
110   * details change type.
111   */
112  private static final byte BER_TYPE_CHANGE_TYPE = (byte) 0x80;
113
114
115
116  /**
117   * The serial version UID for this serializable class.
118   */
119  private static final long serialVersionUID = 8651862605802389433L;
120
121
122
123  // The implementation-specific details for the notification destination.
124  @NotNull private final List<ASN1OctetString> destinationDetails;
125
126  // The change type for the destination details.
127  @NotNull private final SetNotificationDestinationChangeType changeType;
128
129  // The notification destination ID.
130  @NotNull private final String destinationID;
131
132  // The notification manager ID.
133  @NotNull private final String managerID;
134
135
136
137  /**
138   * Creates a new set notification destination extended request with the
139   * provided information.
140   *
141   * @param  managerID           The notification manager ID.  It must not be
142   *                             {@code null}.
143   * @param  destinationID       The notification destination ID.  It must not
144   *                             be {@code null}.
145   * @param  destinationDetails  The implementation-specific details for the
146   *                             notification destination.  At least one detail
147   *                             value must be provided.
148   */
149  public SetNotificationDestinationExtendedRequest(
150              @NotNull final String managerID,
151              @NotNull final String destinationID,
152              @NotNull final ASN1OctetString... destinationDetails)
153  {
154    this(managerID, destinationID, StaticUtils.toList(destinationDetails),
155         SetNotificationDestinationChangeType.REPLACE);
156  }
157
158
159
160  /**
161   * Creates a new set notification destination extended request with the
162   * provided information.
163   *
164   * @param  managerID           The notification manager ID.  It must not be
165   *                             {@code null}.
166   * @param  destinationID       The notification destination ID.  It must not
167   *                             be {@code null}.
168   * @param  destinationDetails  The implementation-specific details for the
169   *                             notification destination.  At least one detail
170   *                             value must be provided.
171   * @param  controls            The set of controls to include in the request.
172   *                             It may be {@code null} or empty if no controls
173   *                             are needed.
174   */
175  public SetNotificationDestinationExtendedRequest(
176              @NotNull final String managerID,
177              @NotNull final String destinationID,
178              @NotNull final Collection<ASN1OctetString> destinationDetails,
179              @Nullable final Control... controls)
180  {
181    this(managerID, destinationID, destinationDetails,
182         SetNotificationDestinationChangeType.REPLACE, controls);
183  }
184
185
186
187  /**
188   * Creates a new set notification destination extended request with the
189   * provided information.
190   *
191   * @param  managerID           The notification manager ID.  It must not be
192   *                             {@code null}.
193   * @param  destinationID       The notification destination ID.  It must not
194   *                             be {@code null}.
195   * @param  destinationDetails  The implementation-specific details for the
196   *                             notification destination.  At least one detail
197   *                             value must be provided.
198   * @param  changeType          The change type for the destination details.
199   * @param  controls            The set of controls to include in the request.
200   *                             It may be {@code null} or empty if no controls
201   *                             are needed.
202   */
203  public SetNotificationDestinationExtendedRequest(
204              @NotNull final String managerID,
205              @NotNull final String destinationID,
206              @NotNull final Collection<ASN1OctetString> destinationDetails,
207              @Nullable final SetNotificationDestinationChangeType changeType,
208              @Nullable final Control... controls)
209  {
210    super(SET_NOTIFICATION_DESTINATION_REQUEST_OID,
211         encodeValue(managerID, destinationID, destinationDetails, changeType),
212         controls);
213
214    this.managerID = managerID;
215    this.destinationID = destinationID;
216    this.destinationDetails =
217         Collections.unmodifiableList(new ArrayList<>(destinationDetails));
218
219    if (changeType == null)
220    {
221      this.changeType = SetNotificationDestinationChangeType.REPLACE;
222    }
223    else
224    {
225      this.changeType = changeType;
226    }
227  }
228
229
230
231  /**
232   * Creates a new set notification destination extended request from the
233   * provided generic extended request.
234   *
235   * @param  extendedRequest  The generic extended request to use to create this
236   *                          set notification destination extended request.
237   *
238   * @throws  LDAPException  If a problem occurs while decoding the request.
239   */
240  public SetNotificationDestinationExtendedRequest(
241              @NotNull final ExtendedRequest extendedRequest)
242         throws LDAPException
243  {
244    super(extendedRequest);
245
246    final ASN1OctetString value = extendedRequest.getValue();
247    if (value == null)
248    {
249      throw new LDAPException(ResultCode.DECODING_ERROR,
250           ERR_SET_NOTIFICATION_DEST_REQ_DECODE_NO_VALUE.get());
251    }
252
253    try
254    {
255      final ASN1Element[] elements =
256           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
257      managerID =
258           ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
259      destinationID =
260           ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
261
262      final ASN1Element[] detailElements =
263           ASN1Sequence.decodeAsSequence(elements[2]).elements();
264      final ArrayList<ASN1OctetString> detailList =
265           new ArrayList<>(detailElements.length);
266      for (final ASN1Element e : detailElements)
267      {
268        detailList.add(ASN1OctetString.decodeAsOctetString(e));
269      }
270      destinationDetails = Collections.unmodifiableList(detailList);
271
272      SetNotificationDestinationChangeType ct =
273           SetNotificationDestinationChangeType.REPLACE;
274      for (int i=3; i < elements.length; i++)
275      {
276        final ASN1Element e = elements[i];
277        switch (e.getType())
278        {
279          case BER_TYPE_CHANGE_TYPE:
280            final int ctIntValue =
281                 ASN1Enumerated.decodeAsEnumerated(e).intValue();
282            ct = SetNotificationDestinationChangeType.valueOf(ctIntValue);
283            if (ct == null)
284            {
285              throw new LDAPException(ResultCode.DECODING_ERROR,
286                   ERR_SET_NOTIFICATION_DEST_REQ_INVALID_CT.get(ctIntValue));
287            }
288            break;
289
290          default:
291            throw new LDAPException(ResultCode.DECODING_ERROR,
292                 ERR_SET_NOTIFICATION_DEST_REQ_INVALID_ELEMENT_TYPE.get(
293                      StaticUtils.toHex(e.getType())));
294        }
295      }
296
297      changeType = ct;
298    }
299    catch (final LDAPException le)
300    {
301      Debug.debugException(le);
302      throw le;
303    }
304    catch (final Exception e)
305    {
306      Debug.debugException(e);
307      throw new LDAPException(ResultCode.DECODING_ERROR,
308           ERR_SET_NOTIFICATION_DEST_REQ_ERROR_DECODING_VALUE.get(
309                StaticUtils.getExceptionMessage(e)),
310           e);
311    }
312  }
313
314
315
316  /**
317   * Encodes the provided information into an ASN.1 octet string suitable for
318   * use as the value of this extended request.
319   *
320   * @param  managerID           The notification manager ID.  It must not be
321   *                             {@code null}.
322   * @param  destinationID       The notification destination ID.  It must not
323   *                             be {@code null}.
324   * @param  destinationDetails  The implementation-specific details for the
325   *                             notification destination.  At least one detail
326   *                             value must be provided.
327   * @param  changeType          The change type for the destination details.
328   *
329   * @return  The ASN.1 octet string containing the encoded value.
330   */
331  @NotNull()
332  private static ASN1OctetString encodeValue(@NotNull final String managerID,
333               @NotNull final String destinationID,
334               @NotNull final Collection<ASN1OctetString> destinationDetails,
335               @Nullable final SetNotificationDestinationChangeType changeType)
336  {
337    Validator.ensureNotNull(managerID);
338    Validator.ensureNotNull(destinationID);
339    Validator.ensureNotNull(destinationDetails);
340    Validator.ensureFalse(destinationDetails.isEmpty());
341
342    final ArrayList<ASN1Element> elements = new ArrayList<>(4);
343    elements.add(new ASN1OctetString(managerID));
344    elements.add(new ASN1OctetString(destinationID));
345    elements.add(new ASN1Sequence(
346         new ArrayList<ASN1Element>(destinationDetails)));
347
348    if ((changeType != null) &&
349        (changeType != SetNotificationDestinationChangeType.REPLACE))
350    {
351      elements.add(new ASN1Enumerated(BER_TYPE_CHANGE_TYPE,
352           changeType.intValue()));
353    }
354
355    return new ASN1OctetString(new ASN1Sequence(elements).encode());
356  }
357
358
359
360  /**
361   * Retrieves the notification manager ID.
362   *
363   * @return  The notification manager ID.
364   */
365  @NotNull()
366  public String getManagerID()
367  {
368    return managerID;
369  }
370
371
372
373  /**
374   * Retrieves the notification destination ID.
375   *
376   * @return  The notification destination ID.
377   */
378  @NotNull()
379  public String getDestinationID()
380  {
381    return destinationID;
382  }
383
384
385
386  /**
387   * Retrieves the implementation-specific details for the notification
388   * destination.
389   *
390   * @return  The implementation-specific details for the notification
391   *          destination.
392   */
393  @NotNull()
394  public List<ASN1OctetString> getDestinationDetails()
395  {
396    return destinationDetails;
397  }
398
399
400
401  /**
402   * Retrieves the change type for the destination details.
403   *
404   * @return  The change type for the destination details.
405   */
406  @NotNull()
407  public SetNotificationDestinationChangeType getChangeType()
408  {
409    return changeType;
410  }
411
412
413
414  /**
415   * {@inheritDoc}
416   */
417  @Override()
418  @NotNull()
419  public SetNotificationDestinationExtendedRequest duplicate()
420  {
421    return duplicate(getControls());
422  }
423
424
425
426  /**
427   * {@inheritDoc}
428   */
429  @Override()
430  @NotNull()
431  public SetNotificationDestinationExtendedRequest duplicate(
432              @Nullable final Control[] controls)
433  {
434    final SetNotificationDestinationExtendedRequest r =
435         new SetNotificationDestinationExtendedRequest(managerID,
436              destinationID, destinationDetails, changeType, controls);
437    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
438    return r;
439  }
440
441
442
443  /**
444   * {@inheritDoc}
445   */
446  @Override()
447  @NotNull()
448  public String getExtendedRequestName()
449  {
450    return INFO_EXTENDED_REQUEST_NAME_SET_NOTIFICATION_DEST.get();
451  }
452
453
454
455  /**
456   * {@inheritDoc}
457   */
458  @Override()
459  public void toString(@NotNull final StringBuilder buffer)
460  {
461    buffer.append("SetNotificationDestinationExtendedRequest(managerID='");
462    buffer.append(managerID);
463    buffer.append("', destinationID='");
464    buffer.append(destinationID);
465    buffer.append("', destinationDetails=ASN1OctetString[");
466    buffer.append(destinationDetails.size());
467    buffer.append("], changeType=");
468    buffer.append(changeType.name());
469
470    final Control[] controls = getControls();
471    if (controls.length > 0)
472    {
473      buffer.append(", controls={");
474      for (int i=0; i < controls.length; i++)
475      {
476        if (i > 0)
477        {
478          buffer.append(", ");
479        }
480
481        buffer.append(controls[i]);
482      }
483      buffer.append('}');
484    }
485
486    buffer.append(')');
487  }
488}