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 Alcatel-Lucent 8661
056 *   server products.  These classes provide support for proprietary
057 *   functionality or for external specifications that are not considered stable
058 *   or mature enough to be guaranteed to work in an interoperable way with
059 *   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 =
154             new ArrayList<String>(propElements.length);
155        for (final ASN1Element e : propElements)
156        {
157          propList.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
158        }
159        properties = Collections.unmodifiableList(propList);
160      }
161      else
162      {
163        properties = Collections.emptyList();
164      }
165    }
166    catch (final Exception e)
167    {
168      Debug.debugException(e);
169      throw new LDAPException(ResultCode.DECODING_ERROR,
170           ERR_GET_BACKUP_COMPAT_RESULT_ERROR_PARSING_VALUE.get(
171                StaticUtils.getExceptionMessage(e)),
172           e);
173    }
174  }
175
176
177
178  /**
179   * Creates a new get backup compatibility descriptor extended result with the
180   * provided information.
181   *
182   * @param  messageID          The message ID for the LDAP message that is
183   *                            associated with this LDAP result.
184   * @param  resultCode         The result code from the response.
185   * @param  diagnosticMessage  The diagnostic message from the response, if
186   *                            available.
187   * @param  matchedDN          The matched DN from the response, if available.
188   * @param  referralURLs       The set of referral URLs from the response, if
189   *                            available.
190   * @param  descriptor         The backup compatibility descriptor value.  It
191   *                            may be {@code null} for an unsuccessful result.
192   * @param  properties         A list of properties that provide information
193   *                            about the way the descriptor may be used.  It
194   *                            may be {@code null} or empty for an unsuccessful
195   *                            result, or if there are no properties.
196   * @param  responseControls   The set of controls from the response, if
197   *                            available.
198   */
199  public GetBackupCompatibilityDescriptorExtendedResult(final int messageID,
200              final ResultCode resultCode, final String diagnosticMessage,
201              final String matchedDN, final String[] referralURLs,
202              final ASN1OctetString descriptor,
203              final Collection<String> properties,
204              final Control... responseControls)
205  {
206    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
207         ((descriptor == null) ? null :
208              GET_BACKUP_COMPATIBILITY_DESCRIPTOR_RESULT_OID),
209         encodeValue(descriptor, properties), responseControls);
210
211    if (descriptor == null)
212    {
213      this.descriptor = null;
214    }
215    else
216    {
217      this.descriptor =
218           new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue());
219    }
220
221    if (properties == null)
222    {
223      this.properties = Collections.emptyList();
224    }
225    else
226    {
227      this.properties =
228           Collections.unmodifiableList(new ArrayList<String>(properties));
229    }
230  }
231
232
233
234  /**
235   * Creates an ASN.1 octet string containing an encoded representation of the
236   * value for a get backup compatibility descriptor extended result with the
237   * provided information.
238   *
239   * @param  descriptor  The backup compatibility descriptor value.  It may be
240   *                     {@code null} for an unsuccessful result.
241   * @param  properties  A list of properties that provide information about the
242   *                     way the descriptor may be used.  It may be {@code null}
243   *                     or empty for an unsuccessful result, or if there are no
244   *                     properties.
245   *
246   * @return  An ASN.1 octet string containing an encoded representation of the
247   *          value for a get backup compatibility descriptor extended result,
248   *          or {@code null} if a result with the provided information should
249   *          not have a value.
250   */
251  public static ASN1OctetString encodeValue(final ASN1OctetString descriptor,
252                                            final Collection<String> properties)
253  {
254    if (descriptor == null)
255    {
256      Validator.ensureTrue(((properties == null) || properties.isEmpty()),
257           "The properties must be null or empty if the descriptor is null.");
258      return null;
259    }
260
261    final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
262    elements.add(new ASN1OctetString(TYPE_DESCRIPTOR, descriptor.getValue()));
263
264    if ((properties != null) && (! properties.isEmpty()))
265    {
266      final ArrayList<ASN1Element> propElements =
267           new ArrayList<ASN1Element>(properties.size());
268      for (final String property : properties)
269      {
270        propElements.add(new ASN1OctetString(property));
271      }
272      elements.add(new ASN1Sequence(TYPE_PROPERTIES, propElements));
273    }
274
275    return new ASN1OctetString(new ASN1Sequence(elements).encode());
276  }
277
278
279
280  /**
281   * Retrieves the backup compatibility descriptor value, if available.
282   *
283   * @return  The backup compatibility descriptor value, or {@code null} if none
284   *          was provided.
285   */
286  public ASN1OctetString getDescriptor()
287  {
288    return descriptor;
289  }
290
291
292
293  /**
294   * Retrieves a list of properties that provide information about the way the
295   * descriptor may be used.
296   *
297   * @return  A list of properties that provide information about the way the
298   *          descriptor may be used, or an empty list if no properties were
299   *          provided.
300   */
301  public List<String> getProperties()
302  {
303    return properties;
304  }
305
306
307
308  /**
309   * {@inheritDoc}
310   */
311  @Override()
312  public String getExtendedResultName()
313  {
314    return INFO_EXTENDED_RESULT_NAME_GET_BACKUP_COMPAT.get();
315  }
316
317
318
319  /**
320   * {@inheritDoc}
321   */
322  @Override()
323  public void toString(final StringBuilder buffer)
324  {
325    buffer.append("GetBackupCompatibilityDescriptorExtendedResult(resultCode=");
326    buffer.append(getResultCode());
327
328    final int messageID = getMessageID();
329    if (messageID >= 0)
330    {
331      buffer.append(", messageID=");
332      buffer.append(messageID);
333    }
334
335    if (descriptor != null)
336    {
337      buffer.append(", descriptorLength=");
338      buffer.append(descriptor.getValueLength());
339    }
340
341    if (! properties.isEmpty())
342    {
343      buffer.append(", descriptorProperties={");
344
345      final Iterator<String> iterator = properties.iterator();
346      while (iterator.hasNext())
347      {
348        buffer.append('\'');
349        buffer.append(iterator.next());
350        buffer.append('\'');
351
352        if (iterator.hasNext())
353        {
354          buffer.append(',');
355        }
356      }
357
358      buffer.append('}');
359    }
360
361    final String diagnosticMessage = getDiagnosticMessage();
362    if (diagnosticMessage != null)
363    {
364      buffer.append(", diagnosticMessage='");
365      buffer.append(diagnosticMessage);
366      buffer.append('\'');
367    }
368
369    final String matchedDN = getMatchedDN();
370    if (matchedDN != null)
371    {
372      buffer.append(", matchedDN='");
373      buffer.append(matchedDN);
374      buffer.append('\'');
375    }
376
377    final String[] referralURLs = getReferralURLs();
378    if (referralURLs.length > 0)
379    {
380      buffer.append(", referralURLs={");
381      for (int i=0; i < referralURLs.length; i++)
382      {
383        if (i > 0)
384        {
385          buffer.append(", ");
386        }
387
388        buffer.append('\'');
389        buffer.append(referralURLs[i]);
390        buffer.append('\'');
391      }
392      buffer.append('}');
393    }
394
395    final Control[] responseControls = getResponseControls();
396    if (responseControls.length > 0)
397    {
398      buffer.append(", responseControls={");
399      for (int i=0; i < responseControls.length; i++)
400      {
401        if (i > 0)
402        {
403          buffer.append(", ");
404        }
405
406        buffer.append(responseControls[i]);
407      }
408      buffer.append('}');
409    }
410
411    buffer.append(')');
412  }
413}