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.util.ArrayList;
041import java.util.Collection;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.List;
045
046import com.unboundid.asn1.ASN1Element;
047import com.unboundid.asn1.ASN1OctetString;
048import com.unboundid.asn1.ASN1Sequence;
049import com.unboundid.ldap.sdk.Control;
050import com.unboundid.ldap.sdk.ExtendedResult;
051import com.unboundid.ldap.sdk.LDAPException;
052import com.unboundid.ldap.sdk.ResultCode;
053import com.unboundid.util.Debug;
054import com.unboundid.util.NotNull;
055import com.unboundid.util.Nullable;
056import com.unboundid.util.StaticUtils;
057import com.unboundid.util.ThreadSafety;
058import com.unboundid.util.ThreadSafetyLevel;
059import com.unboundid.util.Validator;
060
061import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
062
063
064
065/**
066 * This class provides an implementation of an extended result that can be used
067 * to retrieve backup compatibility data for a Directory Server backend.
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 * The OID for this extended result is 1.3.6.1.4.1.30221.2.6.31.  If the request
080 * was processed successfully, then the response will have a value with the
081 * following encoding:
082 * <PRE>
083 *   GetBackupCompatibilityDescriptorResult ::= SEQUENCE {
084 *        descriptor     [0] OCTET STRING,
085 *        properties     [1] SEQUENCE OF OCTET STRING OPTIONAL,
086 *        ... }
087 * </PRE>
088 *
089 * @see  GetBackupCompatibilityDescriptorExtendedRequest
090 * @see  IdentifyBackupCompatibilityProblemsExtendedRequest
091 */
092@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
093public final class GetBackupCompatibilityDescriptorExtendedResult
094       extends ExtendedResult
095{
096  /**
097   * The OID (1.3.6.1.4.1.30221.2.6.31) for the get backup compatibility
098   * descriptor extended result.
099   */
100  @NotNull public static final String
101       GET_BACKUP_COMPATIBILITY_DESCRIPTOR_RESULT_OID =
102            "1.3.6.1.4.1.30221.2.6.31";
103
104
105
106  /**
107   * The BER type for the descriptor element in the value sequence.
108   */
109  private static final byte TYPE_DESCRIPTOR = (byte) 0x80;
110
111
112
113  /**
114   * The BER type for the properties element in the value sequence.
115   */
116  private static final byte TYPE_PROPERTIES = (byte) 0xA1;
117
118
119
120  /**
121   * The serial version UID for this serializable class.
122   */
123  private static final long serialVersionUID = -2493658329210480765L;
124
125
126
127  // The backup compatibility descriptor token.
128  @Nullable private final ASN1OctetString descriptor;
129
130  // A list of properties providing information about the backup compatibility
131  // descriptor.
132  @NotNull private final List<String> properties;
133
134
135
136  /**
137   * Creates a new get backup compatibility descriptor extended result from the
138   * provided generic extended result.
139   *
140   * @param  result  The generic extended result to be decoded as a get backup
141   *                 compatibility descriptor extended result.
142   *
143   * @throws LDAPException  If the provided extended result cannot be parsed as
144   *                        a valid get backup compatibility descriptor
145   *                        extended result.
146   */
147  public GetBackupCompatibilityDescriptorExtendedResult(
148              @NotNull final ExtendedResult result)
149         throws LDAPException
150  {
151    super(result);
152
153    final ASN1OctetString value = result.getValue();
154    if (value == null)
155    {
156      descriptor = null;
157      properties = Collections.emptyList();
158      return;
159    }
160
161    try
162    {
163      final ASN1Element[] elements =
164           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
165      descriptor = elements[0].decodeAsOctetString();
166
167      if (elements.length > 1)
168      {
169        final ASN1Element[] propElements =
170             ASN1Sequence.decodeAsSequence(elements[1]).elements();
171        final ArrayList<String> propList = new ArrayList<>(propElements.length);
172        for (final ASN1Element e : propElements)
173        {
174          propList.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
175        }
176        properties = Collections.unmodifiableList(propList);
177      }
178      else
179      {
180        properties = Collections.emptyList();
181      }
182    }
183    catch (final Exception e)
184    {
185      Debug.debugException(e);
186      throw new LDAPException(ResultCode.DECODING_ERROR,
187           ERR_GET_BACKUP_COMPAT_RESULT_ERROR_PARSING_VALUE.get(
188                StaticUtils.getExceptionMessage(e)),
189           e);
190    }
191  }
192
193
194
195  /**
196   * Creates a new get backup compatibility descriptor extended result with the
197   * provided information.
198   *
199   * @param  messageID          The message ID for the LDAP message that is
200   *                            associated with this LDAP result.
201   * @param  resultCode         The result code from the response.
202   * @param  diagnosticMessage  The diagnostic message from the response, if
203   *                            available.
204   * @param  matchedDN          The matched DN from the response, if available.
205   * @param  referralURLs       The set of referral URLs from the response, if
206   *                            available.
207   * @param  descriptor         The backup compatibility descriptor value.  It
208   *                            may be {@code null} for an unsuccessful result.
209   * @param  properties         A list of properties that provide information
210   *                            about the way the descriptor may be used.  It
211   *                            may be {@code null} or empty for an unsuccessful
212   *                            result, or if there are no properties.
213   * @param  responseControls   The set of controls from the response, if
214   *                            available.
215   */
216  public GetBackupCompatibilityDescriptorExtendedResult(final int messageID,
217              @NotNull final ResultCode resultCode,
218              @Nullable final String diagnosticMessage,
219              @Nullable final String matchedDN,
220              @Nullable final String[] referralURLs,
221              @Nullable final ASN1OctetString descriptor,
222              @Nullable final Collection<String> properties,
223              @Nullable final Control... responseControls)
224  {
225    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
226         ((descriptor == null) ? null :
227              GET_BACKUP_COMPATIBILITY_DESCRIPTOR_RESULT_OID),
228         encodeValue(descriptor, properties), responseControls);
229
230    if (descriptor == null)
231    {
232      this.descriptor = null;
233    }
234    else
235    {
236      this.descriptor =
237           new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue());
238    }
239
240    if (properties == null)
241    {
242      this.properties = Collections.emptyList();
243    }
244    else
245    {
246      this.properties =
247           Collections.unmodifiableList(new ArrayList<>(properties));
248    }
249  }
250
251
252
253  /**
254   * Creates an ASN.1 octet string containing an encoded representation of the
255   * value for a get backup compatibility descriptor extended result with the
256   * provided information.
257   *
258   * @param  descriptor  The backup compatibility descriptor value.  It may be
259   *                     {@code null} for an unsuccessful result.
260   * @param  properties  A list of properties that provide information about the
261   *                     way the descriptor may be used.  It may be {@code null}
262   *                     or empty for an unsuccessful result, or if there are no
263   *                     properties.
264   *
265   * @return  An ASN.1 octet string containing an encoded representation of the
266   *          value for a get backup compatibility descriptor extended result,
267   *          or {@code null} if a result with the provided information should
268   *          not have a value.
269   */
270  @Nullable()
271  public static ASN1OctetString encodeValue(
272              @Nullable final ASN1OctetString descriptor,
273              @Nullable final Collection<String> properties)
274  {
275    if (descriptor == null)
276    {
277      Validator.ensureTrue(((properties == null) || properties.isEmpty()),
278           "The properties must be null or empty if the descriptor is null.");
279      return null;
280    }
281
282    final ArrayList<ASN1Element> elements = new ArrayList<>(2);
283    elements.add(new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue()));
284
285    if ((properties != null) && (! properties.isEmpty()))
286    {
287      final ArrayList<ASN1Element> propElements =
288           new ArrayList<>(properties.size());
289      for (final String property : properties)
290      {
291        propElements.add(new ASN1OctetString(property));
292      }
293      elements.add(new ASN1Sequence(TYPE_PROPERTIES, propElements));
294    }
295
296    return new ASN1OctetString(new ASN1Sequence(elements).encode());
297  }
298
299
300
301  /**
302   * Retrieves the backup compatibility descriptor value, if available.
303   *
304   * @return  The backup compatibility descriptor value, or {@code null} if none
305   *          was provided.
306   */
307  @Nullable()
308  public ASN1OctetString getDescriptor()
309  {
310    return descriptor;
311  }
312
313
314
315  /**
316   * Retrieves a list of properties that provide information about the way the
317   * descriptor may be used.
318   *
319   * @return  A list of properties that provide information about the way the
320   *          descriptor may be used, or an empty list if no properties were
321   *          provided.
322   */
323  @NotNull()
324  public List<String> getProperties()
325  {
326    return properties;
327  }
328
329
330
331  /**
332   * {@inheritDoc}
333   */
334  @Override()
335  @NotNull()
336  public String getExtendedResultName()
337  {
338    return INFO_EXTENDED_RESULT_NAME_GET_BACKUP_COMPAT.get();
339  }
340
341
342
343  /**
344   * {@inheritDoc}
345   */
346  @Override()
347  public void toString(@NotNull final StringBuilder buffer)
348  {
349    buffer.append("GetBackupCompatibilityDescriptorExtendedResult(resultCode=");
350    buffer.append(getResultCode());
351
352    final int messageID = getMessageID();
353    if (messageID >= 0)
354    {
355      buffer.append(", messageID=");
356      buffer.append(messageID);
357    }
358
359    if (descriptor != null)
360    {
361      buffer.append(", descriptorLength=");
362      buffer.append(descriptor.getValueLength());
363    }
364
365    if (! properties.isEmpty())
366    {
367      buffer.append(", descriptorProperties={");
368
369      final Iterator<String> iterator = properties.iterator();
370      while (iterator.hasNext())
371      {
372        buffer.append('\'');
373        buffer.append(iterator.next());
374        buffer.append('\'');
375
376        if (iterator.hasNext())
377        {
378          buffer.append(',');
379        }
380      }
381
382      buffer.append('}');
383    }
384
385    final String diagnosticMessage = getDiagnosticMessage();
386    if (diagnosticMessage != null)
387    {
388      buffer.append(", diagnosticMessage='");
389      buffer.append(diagnosticMessage);
390      buffer.append('\'');
391    }
392
393    final String matchedDN = getMatchedDN();
394    if (matchedDN != null)
395    {
396      buffer.append(", matchedDN='");
397      buffer.append(matchedDN);
398      buffer.append('\'');
399    }
400
401    final String[] referralURLs = getReferralURLs();
402    if (referralURLs.length > 0)
403    {
404      buffer.append(", referralURLs={");
405      for (int i=0; i < referralURLs.length; i++)
406      {
407        if (i > 0)
408        {
409          buffer.append(", ");
410        }
411
412        buffer.append('\'');
413        buffer.append(referralURLs[i]);
414        buffer.append('\'');
415      }
416      buffer.append('}');
417    }
418
419    final Control[] responseControls = getResponseControls();
420    if (responseControls.length > 0)
421    {
422      buffer.append(", responseControls={");
423      for (int i=0; i < responseControls.length; i++)
424      {
425        if (i > 0)
426        {
427          buffer.append(", ");
428        }
429
430        buffer.append(responseControls[i]);
431      }
432      buffer.append('}');
433    }
434
435    buffer.append(')');
436  }
437}