001/*
002 * Copyright 2013-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.extensions;
022
023
024
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.Collections;
028import java.util.Iterator;
029import java.util.List;
030
031import com.unboundid.asn1.ASN1Element;
032import com.unboundid.asn1.ASN1OctetString;
033import com.unboundid.asn1.ASN1Sequence;
034import com.unboundid.ldap.sdk.Control;
035import com.unboundid.ldap.sdk.ExtendedResult;
036import com.unboundid.ldap.sdk.LDAPException;
037import com.unboundid.ldap.sdk.ResultCode;
038import com.unboundid.util.Debug;
039import com.unboundid.util.StaticUtils;
040import com.unboundid.util.ThreadSafety;
041import com.unboundid.util.ThreadSafetyLevel;
042import com.unboundid.util.Validator;
043
044import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
045
046
047
048/**
049 * This class provides an implementation of an extended result that can be used
050 * to retrieve backup compatibility data for a Directory Server backend.
051 * <BR>
052 * <BLOCKQUOTE>
053 *   <B>NOTE:</B>  This class, and other classes within the
054 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
055 *   supported for use against Ping Identity, UnboundID, and
056 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
057 *   for proprietary functionality or for external specifications that are not
058 *   considered stable or mature enough to be guaranteed to work in an
059 *   interoperable way with other types of LDAP servers.
060 * </BLOCKQUOTE>
061 * <BR>
062 * The OID for this extended result is 1.3.6.1.4.1.30221.2.6.31.  If the request
063 * was processed successfully, then the response will have a value with the
064 * following encoding:
065 * <PRE>
066 *   GetBackupCompatibilityDescriptorResult ::= SEQUENCE {
067 *        descriptor     [0] OCTET STRING,
068 *        properties     [1] SEQUENCE OF OCTET STRING OPTIONAL,
069 *        ... }
070 * </PRE>
071 *
072 * @see  GetBackupCompatibilityDescriptorExtendedRequest
073 * @see  IdentifyBackupCompatibilityProblemsExtendedRequest
074 */
075@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
076public final class GetBackupCompatibilityDescriptorExtendedResult
077       extends ExtendedResult
078{
079  /**
080   * The OID (1.3.6.1.4.1.30221.2.6.31) for the get backup compatibility
081   * descriptor extended result.
082   */
083  public static final String GET_BACKUP_COMPATIBILITY_DESCRIPTOR_RESULT_OID =
084       "1.3.6.1.4.1.30221.2.6.31";
085
086
087
088  /**
089   * The BER type for the descriptor element in the value sequence.
090   */
091  private static final byte TYPE_DESCRIPTOR = (byte) 0x80;
092
093
094
095  /**
096   * The BER type for the properties element in the value sequence.
097   */
098  private static final byte TYPE_PROPERTIES = (byte) 0xA1;
099
100
101
102  /**
103   * The serial version UID for this serializable class.
104   */
105  private static final long serialVersionUID = -2493658329210480765L;
106
107
108
109  // The backup compatibility descriptor token.
110  private final ASN1OctetString descriptor;
111
112  // A list of properties providing information about the backup compatibility
113  // descriptor.
114  private final List<String> properties;
115
116
117
118  /**
119   * Creates a new get backup compatibility descriptor extended result from the
120   * provided generic extended result.
121   *
122   * @param  result  The generic extended result to be decoded as a get backup
123   *                 compatibility descriptor extended result.
124   *
125   * @throws LDAPException  If the provided extended result cannot be parsed as
126   *                        a valid get backup compatibility descriptor
127   *                        extended result.
128   */
129  public GetBackupCompatibilityDescriptorExtendedResult(
130       final ExtendedResult result)
131       throws LDAPException
132  {
133    super(result);
134
135    final ASN1OctetString value = result.getValue();
136    if (value == null)
137    {
138      descriptor = null;
139      properties = Collections.emptyList();
140      return;
141    }
142
143    try
144    {
145      final ASN1Element[] elements =
146           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
147      descriptor = elements[0].decodeAsOctetString();
148
149      if (elements.length > 1)
150      {
151        final ASN1Element[] propElements =
152             ASN1Sequence.decodeAsSequence(elements[1]).elements();
153        final ArrayList<String> propList = new ArrayList<>(propElements.length);
154        for (final ASN1Element e : propElements)
155        {
156          propList.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
157        }
158        properties = Collections.unmodifiableList(propList);
159      }
160      else
161      {
162        properties = Collections.emptyList();
163      }
164    }
165    catch (final Exception e)
166    {
167      Debug.debugException(e);
168      throw new LDAPException(ResultCode.DECODING_ERROR,
169           ERR_GET_BACKUP_COMPAT_RESULT_ERROR_PARSING_VALUE.get(
170                StaticUtils.getExceptionMessage(e)),
171           e);
172    }
173  }
174
175
176
177  /**
178   * Creates a new get backup compatibility descriptor extended result with the
179   * provided information.
180   *
181   * @param  messageID          The message ID for the LDAP message that is
182   *                            associated with this LDAP result.
183   * @param  resultCode         The result code from the response.
184   * @param  diagnosticMessage  The diagnostic message from the response, if
185   *                            available.
186   * @param  matchedDN          The matched DN from the response, if available.
187   * @param  referralURLs       The set of referral URLs from the response, if
188   *                            available.
189   * @param  descriptor         The backup compatibility descriptor value.  It
190   *                            may be {@code null} for an unsuccessful result.
191   * @param  properties         A list of properties that provide information
192   *                            about the way the descriptor may be used.  It
193   *                            may be {@code null} or empty for an unsuccessful
194   *                            result, or if there are no properties.
195   * @param  responseControls   The set of controls from the response, if
196   *                            available.
197   */
198  public GetBackupCompatibilityDescriptorExtendedResult(final int messageID,
199              final ResultCode resultCode, final String diagnosticMessage,
200              final String matchedDN, final String[] referralURLs,
201              final ASN1OctetString descriptor,
202              final Collection<String> properties,
203              final Control... responseControls)
204  {
205    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
206         ((descriptor == null) ? null :
207              GET_BACKUP_COMPATIBILITY_DESCRIPTOR_RESULT_OID),
208         encodeValue(descriptor, properties), responseControls);
209
210    if (descriptor == null)
211    {
212      this.descriptor = null;
213    }
214    else
215    {
216      this.descriptor =
217           new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue());
218    }
219
220    if (properties == null)
221    {
222      this.properties = Collections.emptyList();
223    }
224    else
225    {
226      this.properties =
227           Collections.unmodifiableList(new ArrayList<>(properties));
228    }
229  }
230
231
232
233  /**
234   * Creates an ASN.1 octet string containing an encoded representation of the
235   * value for a get backup compatibility descriptor extended result with the
236   * provided information.
237   *
238   * @param  descriptor  The backup compatibility descriptor value.  It may be
239   *                     {@code null} for an unsuccessful result.
240   * @param  properties  A list of properties that provide information about the
241   *                     way the descriptor may be used.  It may be {@code null}
242   *                     or empty for an unsuccessful result, or if there are no
243   *                     properties.
244   *
245   * @return  An ASN.1 octet string containing an encoded representation of the
246   *          value for a get backup compatibility descriptor extended result,
247   *          or {@code null} if a result with the provided information should
248   *          not have a value.
249   */
250  public static ASN1OctetString encodeValue(final ASN1OctetString descriptor,
251                                            final Collection<String> properties)
252  {
253    if (descriptor == null)
254    {
255      Validator.ensureTrue(((properties == null) || properties.isEmpty()),
256           "The properties must be null or empty if the descriptor is null.");
257      return null;
258    }
259
260    final ArrayList<ASN1Element> elements = new ArrayList<>(2);
261    elements.add(new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue()));
262
263    if ((properties != null) && (! properties.isEmpty()))
264    {
265      final ArrayList<ASN1Element> propElements =
266           new ArrayList<>(properties.size());
267      for (final String property : properties)
268      {
269        propElements.add(new ASN1OctetString(property));
270      }
271      elements.add(new ASN1Sequence(TYPE_PROPERTIES, propElements));
272    }
273
274    return new ASN1OctetString(new ASN1Sequence(elements).encode());
275  }
276
277
278
279  /**
280   * Retrieves the backup compatibility descriptor value, if available.
281   *
282   * @return  The backup compatibility descriptor value, or {@code null} if none
283   *          was provided.
284   */
285  public ASN1OctetString getDescriptor()
286  {
287    return descriptor;
288  }
289
290
291
292  /**
293   * Retrieves a list of properties that provide information about the way the
294   * descriptor may be used.
295   *
296   * @return  A list of properties that provide information about the way the
297   *          descriptor may be used, or an empty list if no properties were
298   *          provided.
299   */
300  public List<String> getProperties()
301  {
302    return properties;
303  }
304
305
306
307  /**
308   * {@inheritDoc}
309   */
310  @Override()
311  public String getExtendedResultName()
312  {
313    return INFO_EXTENDED_RESULT_NAME_GET_BACKUP_COMPAT.get();
314  }
315
316
317
318  /**
319   * {@inheritDoc}
320   */
321  @Override()
322  public void toString(final StringBuilder buffer)
323  {
324    buffer.append("GetBackupCompatibilityDescriptorExtendedResult(resultCode=");
325    buffer.append(getResultCode());
326
327    final int messageID = getMessageID();
328    if (messageID >= 0)
329    {
330      buffer.append(", messageID=");
331      buffer.append(messageID);
332    }
333
334    if (descriptor != null)
335    {
336      buffer.append(", descriptorLength=");
337      buffer.append(descriptor.getValueLength());
338    }
339
340    if (! properties.isEmpty())
341    {
342      buffer.append(", descriptorProperties={");
343
344      final Iterator<String> iterator = properties.iterator();
345      while (iterator.hasNext())
346      {
347        buffer.append('\'');
348        buffer.append(iterator.next());
349        buffer.append('\'');
350
351        if (iterator.hasNext())
352        {
353          buffer.append(',');
354        }
355      }
356
357      buffer.append('}');
358    }
359
360    final String diagnosticMessage = getDiagnosticMessage();
361    if (diagnosticMessage != null)
362    {
363      buffer.append(", diagnosticMessage='");
364      buffer.append(diagnosticMessage);
365      buffer.append('\'');
366    }
367
368    final String matchedDN = getMatchedDN();
369    if (matchedDN != null)
370    {
371      buffer.append(", matchedDN='");
372      buffer.append(matchedDN);
373      buffer.append('\'');
374    }
375
376    final String[] referralURLs = getReferralURLs();
377    if (referralURLs.length > 0)
378    {
379      buffer.append(", referralURLs={");
380      for (int i=0; i < referralURLs.length; i++)
381      {
382        if (i > 0)
383        {
384          buffer.append(", ");
385        }
386
387        buffer.append('\'');
388        buffer.append(referralURLs[i]);
389        buffer.append('\'');
390      }
391      buffer.append('}');
392    }
393
394    final Control[] responseControls = getResponseControls();
395    if (responseControls.length > 0)
396    {
397      buffer.append(", responseControls={");
398      for (int i=0; i < responseControls.length; i++)
399      {
400        if (i > 0)
401        {
402          buffer.append(", ");
403        }
404
405        buffer.append(responseControls[i]);
406      }
407      buffer.append('}');
408    }
409
410    buffer.append(')');
411  }
412}