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