001/*
002 * Copyright 2013-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2013-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) 2013-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.io.ByteArrayInputStream;
041import java.io.InputStream;
042
043import com.unboundid.asn1.ASN1Element;
044import com.unboundid.asn1.ASN1Enumerated;
045import com.unboundid.asn1.ASN1OctetString;
046import com.unboundid.asn1.ASN1Sequence;
047import com.unboundid.ldap.sdk.Control;
048import com.unboundid.ldap.sdk.ExtendedResult;
049import com.unboundid.ldap.sdk.LDAPException;
050import com.unboundid.ldap.sdk.ResultCode;
051import com.unboundid.util.Debug;
052import com.unboundid.util.NotNull;
053import com.unboundid.util.Nullable;
054import com.unboundid.util.StaticUtils;
055import com.unboundid.util.ThreadSafety;
056import com.unboundid.util.ThreadSafetyLevel;
057import com.unboundid.util.Validator;
058
059import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
060
061
062
063/**
064 * This class provides an implementation of an extended result that can be used
065 * to retrieve a version of the server configuration.
066 * <BR>
067 * <BLOCKQUOTE>
068 *   <B>NOTE:</B>  This class, and other classes within the
069 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
070 *   supported for use against Ping Identity, UnboundID, and
071 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
072 *   for proprietary functionality or for external specifications that are not
073 *   considered stable or mature enough to be guaranteed to work in an
074 *   interoperable way with other types of LDAP servers.
075 * </BLOCKQUOTE>
076 * <BR>
077 * The OID for this extended result is 1.3.6.1.4.1.30221.2.6.29.  If the request
078 * was processed successfully, then the response will have a value with the
079 * following encoding:
080 * <PRE>
081 *   GetConfigurationResult ::= SEQUENCE {
082 *        configurationType         [0] ENUMERATED {
083 *             active       (0),
084 *             baseline     (1),
085 *             archived     (2),
086 *             ... },
087 *        fileName                  [1] OCTET STRING,
088 *        configurationFileData     [2] OCTET STRING,
089 *        ... }
090 * </PRE>
091 *
092 * @see  GetConfigurationExtendedRequest
093 * @see  ListConfigurationsExtendedRequest
094 */
095@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
096public final class GetConfigurationExtendedResult
097       extends ExtendedResult
098{
099  /**
100   * The OID (1.3.6.1.4.1.30221.2.6.29) for the get configuration extended
101   * result.
102   */
103  @NotNull public static final String GET_CONFIG_RESULT_OID =
104       "1.3.6.1.4.1.30221.2.6.29";
105
106
107
108  /**
109   * The BER type for the element holding the type of configuration that has
110   * been returned.
111   */
112  private static final byte TYPE_CONFIG_TYPE = (byte) 0x80;
113
114
115
116  /**
117   * The BER type for the element holding the name of the configuration file
118   * that has been returned.
119   */
120  private static final byte TYPE_FILE_NAME = (byte) 0x81;
121
122
123
124  /**
125   * The BER type for the element holding the raw LDIF data that comprises the
126   * configuration file that has been returned.
127   */
128  private static final byte TYPE_FILE_DATA = (byte) 0x82;
129
130
131
132  /**
133   * The serial version UID for this serializable class.
134   */
135  private static final long serialVersionUID = 6042324433827773678L;
136
137
138
139  // The raw data for the configuration file that has been returned.
140  @Nullable private final byte[] fileData;
141
142  // The type of configuration that has been returned.
143  @Nullable private final GetConfigurationType configurationType;
144
145  // The name of the configuration file that has been returned.
146  @Nullable private final String fileName;
147
148
149
150  /**
151   * Creates a new get configuration extended result from the provided generic
152   * extended result.
153   *
154   * @param  result  The generic extended result to be decoded as a get
155   *                 configuration extended result.
156   *
157   * @throws LDAPException  If the provided extended result cannot be parsed as
158   *                         a valid get configuration extended result.
159   */
160  public GetConfigurationExtendedResult(@NotNull final ExtendedResult result)
161       throws LDAPException
162  {
163    super(result);
164
165    final ASN1OctetString value = result.getValue();
166    if (value == null)
167    {
168      configurationType = null;
169      fileName = null;
170      fileData = null;
171      return;
172    }
173
174    try
175    {
176      final ASN1Element[] elements =
177           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
178
179      final int configType =
180           ASN1Enumerated.decodeAsEnumerated(elements[0]).intValue();
181      configurationType = GetConfigurationType.forIntValue(configType);
182      if (configurationType == null)
183      {
184        throw new LDAPException(ResultCode.DECODING_ERROR,
185             ERR_GET_CONFIG_RESULT_INVALID_CONFIG_TYPE.get(configType));
186      }
187
188      fileName = ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
189      fileData = ASN1OctetString.decodeAsOctetString(elements[2]).getValue();
190    }
191    catch (final LDAPException le)
192    {
193      Debug.debugException(le);
194      throw le;
195    }
196    catch (final Exception e)
197    {
198      Debug.debugException(e);
199      throw new LDAPException(ResultCode.DECODING_ERROR,
200           ERR_GET_CONFIG_RESULT_ERROR_PARSING_VALUE.get(
201                StaticUtils.getExceptionMessage(e)),
202           e);
203    }
204  }
205
206
207
208  /**
209   * Creates a new get configuration extended result with the provided
210   * information.
211   *
212   * @param  messageID          The message ID for the LDAP message that is
213   *                            associated with this LDAP result.
214   * @param  resultCode         The result code from the response.
215   * @param  diagnosticMessage  The diagnostic message from the response, if
216   *                            available.
217   * @param  matchedDN          The matched DN from the response, if available.
218   * @param  referralURLs       The set of referral URLs from the response, if
219   *                            available.
220   * @param  configurationType  The type of configuration that has been
221   *                            returned.
222   * @param  fileName           The name of the configuration file that has been
223   *                            returned.
224   * @param  fileData           The raw data for the configuration file that has
225   *                            been returned.
226   * @param  responseControls   The set of controls from the response, if
227   *                            available.
228   */
229  public GetConfigurationExtendedResult(final int messageID,
230              @NotNull final ResultCode resultCode,
231              @Nullable final String diagnosticMessage,
232              @Nullable final String matchedDN,
233              @Nullable final String[] referralURLs,
234              @Nullable final GetConfigurationType configurationType,
235              @Nullable final String fileName,
236              @Nullable final byte[] fileData,
237              @Nullable final Control... responseControls)
238  {
239    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
240         ((configurationType == null) ? null : GET_CONFIG_RESULT_OID),
241         encodeValue(configurationType, fileName, fileData), responseControls);
242
243    this.configurationType = configurationType;
244    this.fileName          = fileName;
245    this.fileData          = fileData;
246  }
247
248
249
250  /**
251   * Creates an ASN.1 octet string containing an encoded representation of the
252   * value for a get configuration extended result with the provided
253   * information.
254   *
255   * @param  configurationType  The type of configuration that has been
256   *                            returned.
257   * @param  fileName           The name of the configuration file that has been
258   *                            returned.
259   * @param  fileData           The raw data for the configuration file that has
260   *                            been returned.
261   *
262   * @return  An ASN.1 octet string containing an encoded representation of the
263   *          value for a get configuration extended result, or {@code null} if
264   *          a result with the provided information should not have a value.
265   */
266  @Nullable()
267  public static ASN1OctetString encodeValue(
268                     @Nullable final GetConfigurationType configurationType,
269                     @Nullable final String fileName,
270                     @Nullable final byte[] fileData)
271  {
272    if (configurationType == null)
273    {
274      Validator.ensureTrue((fileName == null),
275           "The configuration file name must be null if the configuration " +
276                "type is null.");
277      Validator.ensureTrue((fileData == null),
278           "The configuration file data must be null if the configuration " +
279                "type is null.");
280      return null;
281    }
282
283    Validator.ensureTrue((fileName != null),
284         "The configuration file name must not be null if the configuration " +
285              "type is not null.");
286    Validator.ensureTrue((fileData != null),
287         "The configuration file data must not be null if the configuration " +
288              "type is not null.");
289
290    final ASN1Sequence valueSequence = new ASN1Sequence(
291         new ASN1Enumerated(TYPE_CONFIG_TYPE, configurationType.getIntValue()),
292         new ASN1OctetString(TYPE_FILE_NAME, fileName),
293         new ASN1OctetString(TYPE_FILE_DATA, fileData));
294    return new ASN1OctetString(valueSequence.encode());
295  }
296
297
298
299  /**
300   * Retrieves the type of configuration that has been returned, if available.
301   *
302   * @return  The type of configuration that has been returned, or {@code null}
303   *          if this is not available.
304   */
305  @Nullable()
306  public GetConfigurationType getConfigurationType()
307  {
308    return configurationType;
309  }
310
311
312
313  /**
314   * Retrieves the name of the configuration file that has been returned, if
315   * available.
316   *
317   * @return  The name of the configuration file that has been returned, or
318   *          {@code null} if this is not available.
319   */
320  @Nullable()
321  public String getFileName()
322  {
323    return fileName;
324  }
325
326
327
328  /**
329   * Retrieves the raw data for the configuration file that has been returned,
330   * if available.
331   *
332   * @return  The raw data for the configuration file that has been returned,
333   *          or {@code null} if this is not available.
334   */
335  @Nullable()
336  public byte[] getFileData()
337  {
338    return fileData;
339  }
340
341
342
343  /**
344   * Retrieves an input stream that may be used to read the file data that has
345   * been returned, if available.
346   *
347   * @return  An input stream that may be used to read the file data that has
348   *          been returned, or {@code null} if this is not available.
349   */
350  @Nullable()
351  public InputStream getFileDataInputStream()
352  {
353    if (fileData == null)
354    {
355      return null;
356    }
357    else
358    {
359      return new ByteArrayInputStream(fileData);
360    }
361  }
362
363
364
365  /**
366   * {@inheritDoc}
367   */
368  @Override()
369  @NotNull()
370  public String getExtendedResultName()
371  {
372    return INFO_EXTENDED_RESULT_NAME_GET_CONFIG.get();
373  }
374
375
376
377  /**
378   * {@inheritDoc}
379   */
380  @Override()
381  public void toString(@NotNull final StringBuilder buffer)
382  {
383    buffer.append("GetConfigurationExtendedResult(resultCode=");
384    buffer.append(getResultCode());
385
386    final int messageID = getMessageID();
387    if (messageID >= 0)
388    {
389      buffer.append(", messageID=");
390      buffer.append(messageID);
391    }
392
393    if (configurationType != null)
394    {
395      buffer.append(", configType=");
396      buffer.append(configurationType.name());
397    }
398
399    if (fileName != null)
400    {
401      buffer.append(", fileName='");
402      buffer.append(fileName);
403      buffer.append('\'');
404    }
405
406    if (fileData != null)
407    {
408      buffer.append(", fileLength=");
409      buffer.append(fileData.length);
410    }
411
412    final String diagnosticMessage = getDiagnosticMessage();
413    if (diagnosticMessage != null)
414    {
415      buffer.append(", diagnosticMessage='");
416      buffer.append(diagnosticMessage);
417      buffer.append('\'');
418    }
419
420    final String matchedDN = getMatchedDN();
421    if (matchedDN != null)
422    {
423      buffer.append(", matchedDN='");
424      buffer.append(matchedDN);
425      buffer.append('\'');
426    }
427
428    final String[] referralURLs = getReferralURLs();
429    if (referralURLs.length > 0)
430    {
431      buffer.append(", referralURLs={");
432      for (int i=0; i < referralURLs.length; i++)
433      {
434        if (i > 0)
435        {
436          buffer.append(", ");
437        }
438
439        buffer.append('\'');
440        buffer.append(referralURLs[i]);
441        buffer.append('\'');
442      }
443      buffer.append('}');
444    }
445
446    final Control[] responseControls = getResponseControls();
447    if (responseControls.length > 0)
448    {
449      buffer.append(", responseControls={");
450      for (int i=0; i < responseControls.length; i++)
451      {
452        if (i > 0)
453        {
454          buffer.append(", ");
455        }
456
457        buffer.append(responseControls[i]);
458      }
459      buffer.append('}');
460    }
461
462    buffer.append(')');
463  }
464}