001/*
002 * Copyright 2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2020 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 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.ASN1Boolean;
041import com.unboundid.asn1.ASN1Element;
042import com.unboundid.asn1.ASN1Long;
043import com.unboundid.asn1.ASN1OctetString;
044import com.unboundid.asn1.ASN1Sequence;
045import com.unboundid.ldap.sdk.Control;
046import com.unboundid.ldap.sdk.IntermediateResponse;
047import com.unboundid.ldap.sdk.LDAPException;
048import com.unboundid.ldap.sdk.ResultCode;
049import com.unboundid.util.Debug;
050import com.unboundid.util.NotMutable;
051import com.unboundid.util.StaticUtils;
052import com.unboundid.util.ThreadSafety;
053import com.unboundid.util.ThreadSafetyLevel;
054
055import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
056
057
058
059/**
060 * This class provides an implementation of an intermediate response that can
061 * provide the client with a portion of the support data archive generated in
062 * response to a {@link CollectSupportDataExtendedRequest}.
063 * <BR>
064 * <BLOCKQUOTE>
065 *   <B>NOTE:</B>  This class, and other classes within the
066 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
067 *   supported for use against Ping Identity, UnboundID, and
068 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
069 *   for proprietary functionality or for external specifications that are not
070 *   considered stable or mature enough to be guaranteed to work in an
071 *   interoperable way with other types of LDAP servers.
072 * </BLOCKQUOTE>
073 * <BR>
074 * The collect support data archive fragment intermediate response has an OID of
075 * 1.3.6.1.4.1.30221.2.6.66 and a value with the following encoding:
076 * <BR>
077 * <PRE>
078 *   CollectSupportDataArchiveDataIntermediateResponse ::= SEQUENCE {
079 *      archiveFileName           [0] OCTET STRING,
080 *      totalArchiveSizeBytes     [1] INTEGER,
081 *      moreDataToReturn          [2] BOOLEAN,
082 *      fragmentData              [3] OCTET STRING,
083 *      ... }
084 * </PRE>
085 *
086 * @see  CollectSupportDataExtendedRequest
087 * @see  CollectSupportDataExtendedResult
088 * @see  CollectSupportDataOutputIntermediateResponse
089 */
090@NotMutable()
091@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
092public final class CollectSupportDataArchiveFragmentIntermediateResponse
093       extends IntermediateResponse
094{
095  /**
096   * The OID (1.3.6.1.4.1.30221.2.6.66) for the collect support data archive
097   * fragment intermediate response.
098   */
099  public static final String
100       COLLECT_SUPPORT_DATA_ARCHIVE_FRAGMENT_INTERMEDIATE_RESPONSE_OID =
101       "1.3.6.1.4.1.30221.2.6.66";
102
103
104
105  /**
106   * The BER type for the value element that holds the name (without any path
107   * information) that the server used for the support data archive.
108   */
109  private static final byte TYPE_ARCHIVE_FILE_NAME = (byte) 0x80;
110
111
112
113  /**
114   * The BER type for the value element that holds the total size of the
115   * support data archive, in bytes.
116   */
117  private static final byte TYPE_TOTAL_ARCHIVE_SIZE_BYTES = (byte) 0x81;
118
119
120
121  /**
122   * The BER type for the value element that indicates whether there is still
123   * more of the support data archive to be returned.
124   */
125  private static final byte TYPE_MORE_DATA_TO_RETURN = (byte) 0x82;
126
127
128
129  /**
130   * The BER type for the value element that holds the data for this fragment of
131   * the support data archive.
132   */
133  private static final byte TYPE_FRAGMENT_DATA = (byte) 0x83;
134
135
136  /**
137   * The serial version UID for this serializable class.
138   */
139  private static final long serialVersionUID = 6989352662115346422L;
140
141
142
143  // Indicates whether there is still more of the support data archive to be
144  // returned to the client.
145  private final boolean moreDataToReturn;
146
147  // The data that comprises this fragment of the support data archive.
148  private final byte[] fragmentData;
149
150  // The total size of the support data archive, in bytes.
151  private final long totalArchiveSizeBytes;
152
153  // The name (without any path information) that the server used for the
154  // support data archive file.
155  private final String archiveFileName;
156
157
158
159  /**
160   * Creates a new collect support data archive fragment intermediate response
161   * object with the provided information.
162   *
163   * @param  archiveFileName        The name (without any path information) that
164   *                                the server used for the support data archive
165   *                                file.  It must not be {@code null}.
166   * @param  totalArchiveSizeBytes  The size, in bytes, of the complete
167   *                                support data archive.
168   * @param  moreDataToReturn       Indicates whether there are more fragments
169   *                                to be returned to as part of the complete
170   *                                support data archive.
171   * @param  fragmentData           The data contained in this fragment of the
172   *                                support data archive.  It must not be
173   *                                {@code null}.
174   * @param  controls               The set of controls to include in this
175   *                                intermediate response.  It may be
176   *                                {@code null} or empty if no controls should
177   *                                be included.
178   */
179  public CollectSupportDataArchiveFragmentIntermediateResponse(
180              final String archiveFileName, final long totalArchiveSizeBytes,
181              final boolean moreDataToReturn, final byte[] fragmentData,
182              final Control... controls)
183  {
184    super(COLLECT_SUPPORT_DATA_ARCHIVE_FRAGMENT_INTERMEDIATE_RESPONSE_OID,
185         encodeValue(archiveFileName, totalArchiveSizeBytes, moreDataToReturn,
186              fragmentData),
187         controls);
188
189    this.archiveFileName = archiveFileName;
190    this.totalArchiveSizeBytes = totalArchiveSizeBytes;
191    this.moreDataToReturn = moreDataToReturn;
192    this.fragmentData = fragmentData;
193  }
194
195
196
197  /**
198   * Constructs an ASN.1 octet string suitable for use as the value of this
199   * collect support data archive fragment intermediate response.
200   *
201   * @param  archiveFileName        The name (without any path information) that
202   *                                the server used for the support data archive
203   *                                file.  It must not be {@code null}.
204   * @param  totalArchiveSizeBytes  The size, in bytes, of the complete
205   *                                support data archive.
206   * @param  moreDataToReturn       Indicates whether there are more fragments
207   *                                to be returned to as part of the complete
208   *                                support data archive.
209   * @param  fragmentData           The data contained in this fragment of the
210   *                                support data archive.  It must not be
211   *                                {@code null}.
212   *
213   * @return  The ASN.1 octet string containing the encoded value.
214   */
215  private static ASN1OctetString encodeValue(final String archiveFileName,
216                                             final long totalArchiveSizeBytes,
217                                             final boolean moreDataToReturn,
218                                             final byte[] fragmentData)
219  {
220    final ASN1Sequence valueSequence = new ASN1Sequence(
221         new ASN1OctetString(TYPE_ARCHIVE_FILE_NAME, archiveFileName),
222         new ASN1Long(TYPE_TOTAL_ARCHIVE_SIZE_BYTES, totalArchiveSizeBytes),
223         new ASN1Boolean(TYPE_MORE_DATA_TO_RETURN, moreDataToReturn),
224         new ASN1OctetString(TYPE_FRAGMENT_DATA, fragmentData));
225    return new ASN1OctetString(valueSequence.encode());
226  }
227
228
229
230  /**
231   * Creates a new collect support data archive fragment intermediate response
232   * that is decoded from the provided generic intermediate response.
233   *
234   * @param  intermediateResponse  The generic intermediate response to be
235   *                               decoded as a collect support data archive
236   *                               fragment intermediate response.  It must not
237   *                               be {@code null}.
238   *
239   * @throws  LDAPException  If the provided intermediate response object cannot
240   *                         be decoded as a collect support data archive
241   *                         fragment intermediate response.
242   */
243  public CollectSupportDataArchiveFragmentIntermediateResponse(
244              final IntermediateResponse intermediateResponse)
245         throws LDAPException
246  {
247    super(intermediateResponse);
248
249    final ASN1OctetString value = intermediateResponse.getValue();
250    if (value == null)
251    {
252      throw new LDAPException(ResultCode.DECODING_ERROR,
253           ERR_CSD_FRAGMENT_IR_DECODE_NO_VALUE.get());
254    }
255
256    try
257    {
258      final ASN1Sequence valueSequence =
259           ASN1Sequence.decodeAsSequence(value.getValue());
260      final ASN1Element[] elements = valueSequence.elements();
261      archiveFileName =
262           ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
263      totalArchiveSizeBytes = ASN1Long.decodeAsLong(elements[1]).longValue();
264      moreDataToReturn =
265           ASN1Boolean.decodeAsBoolean(elements[2]).booleanValue();
266      fragmentData =
267           ASN1OctetString.decodeAsOctetString(elements[3]).getValue();
268    }
269    catch (final Exception e)
270    {
271      Debug.debugException(e);
272      throw new LDAPException(ResultCode.DECODING_ERROR,
273           ERR_CSD_FRAGMENT_IR_DECODE_ERROR.get(
274                StaticUtils.getExceptionMessage(e)),
275           e);
276    }
277  }
278
279
280
281  /**
282   * Retrieves the name (without any path information) that the server used for
283   * the support data archive file.
284   *
285   * @return  The name (without any path information) that the server used for
286   *          the support data archive file.
287   */
288  public String getArchiveFileName()
289  {
290    return archiveFileName;
291  }
292
293
294
295  /**
296   * Retrieves the total number of bytes contained in the complete support data
297   * archive.
298   *
299   * @return  The total number of bytes contained in the complete support data
300   *          archive.
301   */
302  public long getTotalArchiveSizeBytes()
303  {
304    return totalArchiveSizeBytes;
305  }
306
307
308
309  /**
310   * Indicates whether there are one or more fragments still to be returned
311   * in the complete support data archive.
312   *
313   * @return  {@code true} if there are still more fragments to be returned, or
314   *          {@code false} if not.
315   */
316  public boolean moreDataToReturn()
317  {
318    return moreDataToReturn;
319  }
320
321
322
323  /**
324   * Retrieves the data included in this fragment.
325   *
326   * @return  The data included in this fragment.
327   */
328  public byte[] getFragmentData()
329  {
330    return fragmentData;
331  }
332
333
334
335  /**
336   * {@inheritDoc}
337   */
338  @Override()
339  public String getIntermediateResponseName()
340  {
341    return INFO_COLLECT_SUPPORT_DATA_FRAGMENT_IR_NAME.get();
342  }
343
344
345
346  /**
347   * {@inheritDoc}
348   */
349  @Override()
350  public String valueToString()
351  {
352    final StringBuilder buffer = new StringBuilder();
353
354    buffer.append("archiveFileName='");
355    buffer.append(archiveFileName);
356    buffer.append("' totalArchiveSizeBytes=");
357    buffer.append(totalArchiveSizeBytes);
358    buffer.append(" moreDataToReturn=");
359    buffer.append(moreDataToReturn);
360    buffer.append(" fragmentSizeBytes=");
361    buffer.append(fragmentData.length);
362
363    return buffer.toString();
364  }
365
366
367
368  /**
369   * {@inheritDoc}
370   */
371  @Override()
372  public void toString(final StringBuilder buffer)
373  {
374    buffer.append(
375         "CollectSupportDataArchiveFragmentIntermediateResponse(oid='");
376    buffer.append(getOID());
377    buffer.append("', archiveFileName='");
378    buffer.append(archiveFileName);
379    buffer.append("', totalArchiveSizeBytes=");
380    buffer.append(totalArchiveSizeBytes);
381    buffer.append(", moreDataToReturn=");
382    buffer.append(moreDataToReturn);
383    buffer.append(", fragmentSizeBytes=");
384    buffer.append(fragmentData.length);
385
386    final Control[] controls = getControls();
387    if (controls.length > 0)
388    {
389      buffer.append(", controls={");
390      for (int i=0; i < controls.length; i++)
391      {
392        if (i > 0)
393        {
394          buffer.append(", ");
395        }
396
397        buffer.append(controls[i]);
398      }
399      buffer.append('}');
400    }
401
402    buffer.append(')');
403  }
404}