001/*
002 * Copyright 2020-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2020-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) 2020-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 com.unboundid.asn1.ASN1Element;
041import com.unboundid.asn1.ASN1Integer;
042import com.unboundid.asn1.ASN1OctetString;
043import com.unboundid.asn1.ASN1Sequence;
044import com.unboundid.ldap.sdk.Control;
045import com.unboundid.ldap.sdk.ExtendedResult;
046import com.unboundid.ldap.sdk.LDAPException;
047import com.unboundid.ldap.sdk.ResultCode;
048import com.unboundid.util.Debug;
049import com.unboundid.util.NotMutable;
050import com.unboundid.util.NotNull;
051import com.unboundid.util.Nullable;
052import com.unboundid.util.StaticUtils;
053import com.unboundid.util.ThreadSafety;
054import com.unboundid.util.ThreadSafetyLevel;
055
056import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
057
058
059
060/**
061 * This class provides an implementation of an extended result that provides
062 * information about the result of processing a
063 * {@link CollectSupportDataExtendedRequest}.  Once this message has been
064 * received, all processing for the associated request will be complete, and
065 * there should not be any further
066 * {@link CollectSupportDataOutputIntermediateResponse} or
067 * {@link CollectSupportDataArchiveFragmentIntermediateResponse} messages.
068 * <BR>
069 * <BLOCKQUOTE>
070 *   <B>NOTE:</B>  This class, and other classes within the
071 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
072 *   supported for use against Ping Identity, UnboundID, and
073 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
074 *   for proprietary functionality or for external specifications that are not
075 *   considered stable or mature enough to be guaranteed to work in an
076 *   interoperable way with other types of LDAP servers.
077 * </BLOCKQUOTE>
078 * <BR>
079 * If the extended operation processing failed for some reason before the server
080 * could invoke the collect-support-data tool, then this response may not
081 * include an OID or value.  However, if the collect-support-data tool has been
082 * invoked (regardless of its success or failure), then the extended result
083 * should have an OID of1.3.6.1.4.1.30221.2.6.67 and a value with the following
084 * encoding:
085 * <BR>
086 * <PRE>
087 *   CollectSupportDataResponse ::= SEQUENCE {
088 *      exitCode     [0] INTEGER,
089 *      ... }
090 * </PRE>
091 *
092 * @see  CollectSupportDataExtendedRequest
093 * @see  CollectSupportDataArchiveFragmentIntermediateResponse
094 * @see  CollectSupportDataOutputIntermediateResponse
095 */
096@NotMutable()
097@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
098public final class CollectSupportDataExtendedResult
099       extends ExtendedResult
100{
101  /**
102   * The OID (1.3.6.1.4.1.30221.2.6.67) for the collect support data extended
103   * result.
104   */
105  @NotNull public static final String COLLECT_SUPPORT_DATA_RESULT_OID =
106       "1.3.6.1.4.1.30221.2.6.67";
107
108
109
110  /**
111   * The BER type for the value element that holds the collect-support-data tool
112   * exit code.
113   */
114  private static final byte TYPE_EXIT_CODE = (byte) 0x80;
115
116
117
118  /**
119   * The serial version UID for this serializable class.
120   */
121  private static final long serialVersionUID = 9005943853349941187L;
122
123
124
125  // The exit code returned by the collect-support-data tool.
126  @Nullable private final Integer exitCode;
127
128
129
130  /**
131   * Creates a new collect support data extended result with the provided
132   * information.
133   *
134   * @param  messageID          The LDAP message ID for this extended result.
135   * @param  resultCode         The result code for this extended result.  It
136   *                            must not be {@code null}.
137   * @param  diagnosticMessage  The diagnostic message for this extended result.
138   *                            It may be {@code null} if no diagnostic message
139   *                            should be included.
140   * @param  matchedDN          The matched DN for this extended result.  It may
141   *                            be {@code null} if no matched DN should be
142   *                            included.
143   * @param  referralURLs       The set of referral URLs for this extended
144   *                            result.  It may be {@code null} or empty if no
145   *                            referral URLs should be included.
146   * @param  exitCode           The exit code returned when the
147   *                            collect-support-data tool completed.  This may
148   *                            be {@code null} if extended operation processing
149   *                            failed before the collect-support-data tool
150   *                            could complete.
151   * @param  controls           The set of controls to include in the extended
152   *                            result.  It may be [@code null} or empty if no
153   *                            controls should be included.
154   */
155  public CollectSupportDataExtendedResult(final int messageID,
156              @NotNull final ResultCode resultCode,
157              @Nullable final String diagnosticMessage,
158              @Nullable final String matchedDN,
159              @Nullable final String[] referralURLs,
160              @Nullable final Integer exitCode,
161              @Nullable final Control... controls)
162  {
163    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
164         (exitCode == null) ? null : COLLECT_SUPPORT_DATA_RESULT_OID,
165         encodeValue(exitCode), controls);
166
167    this.exitCode = exitCode;
168  }
169
170
171
172  /**
173   * Constructs an ASN.1 octet string suitable for use as the value of this
174   * extended result.
175   *
176   * @param  exitCode  The exit code returned when the collect-support-data tool
177   *                   completed.  This may be {@code null} if extended
178   *                   operation processing failed before the
179   *                   collect-support-data tool could complete.
180   *
181   * @return  The ASN.1 octet string created for use as the value of this
182   *          extended result, or {@code null} if the extended result should not
183   *          have a value.
184   */
185  @Nullable()
186  private static ASN1OctetString encodeValue(@Nullable final Integer exitCode)
187  {
188    if (exitCode == null)
189    {
190      return null;
191    }
192
193    final ASN1Sequence valueSequence = new ASN1Sequence(
194         new ASN1Integer(TYPE_EXIT_CODE, exitCode));
195
196    return new ASN1OctetString(valueSequence.encode());
197  }
198
199
200
201  /**
202   * Creates a new collect support data extended result that is decoded from
203   * the provided generic extended result.
204   *
205   * @param  extendedResult  The generic extended result to be decoded as a
206   *                         collect support data extended result.  It must not
207   *                         be {@code null}.
208   *
209   * @throws  LDAPException  If the provided generic extended result cannot be
210   *                         decoded as a collect support data extended result.
211   */
212  public CollectSupportDataExtendedResult(
213              @NotNull final ExtendedResult extendedResult)
214         throws LDAPException
215  {
216    super(extendedResult);
217
218    final ASN1OctetString value = extendedResult.getValue();
219    if (value == null)
220    {
221      exitCode = null;
222      return;
223    }
224
225    try
226    {
227      final ASN1Sequence valueSequence =
228           ASN1Sequence.decodeAsSequence(value.getValue());
229      final ASN1Element[] elements = valueSequence.elements();
230      exitCode = ASN1Integer.decodeAsInteger(elements[0]).intValue();
231    }
232    catch (final Exception e)
233    {
234      Debug.debugException(e);
235      throw new LDAPException(ResultCode.DECODING_ERROR,
236           ERR_CSD_RESULT_DECODE_ERROR.get(
237                StaticUtils.getExceptionMessage(e)),
238           e);
239    }
240  }
241
242
243
244  /**
245   * Retrieves the exit code returned when the collect-support-data tool
246   * completed.
247   *
248   * @return  The exit code returned when the collect-support-data tool
249   *          completed, or {@code null} if extended operation processing
250   *          failed before the collect-support-data tool could complete.
251   */
252  @Nullable()
253  public Integer getExitCode()
254  {
255    return exitCode;
256  }
257
258
259
260  /**
261   * {@inheritDoc}
262   */
263  @Override()
264  @NotNull()
265  public String getExtendedResultName()
266  {
267    return INFO_COLLECT_SUPPORT_DATA_RESULT_NAME.get();
268  }
269
270
271
272  /**
273   * {@inheritDoc}
274   */
275  @Override()
276  public void toString(@NotNull final StringBuilder buffer)
277  {
278    buffer.append("CollectSupportDataExtendedResult(resultCode=");
279    buffer.append(getResultCode());
280
281    final int messageID = getMessageID();
282    if (messageID >= 0)
283    {
284      buffer.append(", messageID=");
285      buffer.append(messageID);
286    }
287
288    final String diagnosticMessage = getDiagnosticMessage();
289    if (diagnosticMessage != null)
290    {
291      buffer.append(", diagnosticMessage='");
292      buffer.append(diagnosticMessage);
293      buffer.append('\'');
294    }
295
296    final String matchedDN = getMatchedDN();
297    if (matchedDN != null)
298    {
299      buffer.append(", matchedDN='");
300      buffer.append(matchedDN);
301      buffer.append('\'');
302    }
303
304    final String[] referralURLs = getReferralURLs();
305    if (referralURLs.length > 0)
306    {
307      buffer.append(", referralURLs={");
308      for (int i=0; i < referralURLs.length; i++)
309      {
310        if (i > 0)
311        {
312          buffer.append(", ");
313        }
314
315        buffer.append('\'');
316        buffer.append(referralURLs[i]);
317        buffer.append('\'');
318      }
319      buffer.append('}');
320    }
321
322    if (exitCode != null)
323    {
324      buffer.append(", exitCode=");
325      buffer.append(exitCode);
326    }
327
328    final Control[] responseControls = getResponseControls();
329    if (responseControls.length > 0)
330    {
331      buffer.append(", controls={");
332      for (int i=0; i < responseControls.length; i++)
333      {
334        if (i > 0)
335        {
336          buffer.append(", ");
337        }
338
339        buffer.append(responseControls[i]);
340      }
341      buffer.append('}');
342    }
343
344    buffer.append(')');
345  }
346}