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 identify potential incompatibility problems between two backup
051 * compatibility descriptor values.
052 * <BR>
053 * <BLOCKQUOTE>
054 *   <B>NOTE:</B>  This class, and other classes within the
055 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
056 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
057 *   server products.  These classes provide support for proprietary
058 *   functionality or for external specifications that are not considered stable
059 *   or mature enough to be guaranteed to work in an interoperable way with
060 *   other types of LDAP servers.
061 * </BLOCKQUOTE>
062 * <BR>
063 * The OID for this extended result is 1.3.6.1.4.1.30221.2.6.33.  If the request
064 * was processed successfully, then the response will have a value with the
065 * following encoding:
066 * <PRE>
067 *   IdentifyBackupCompatibilityProblemsResult ::= SEQUENCE {
068 *        errorMessages       [0] SEQUENCE OF OCTET STRING OPTIONAL,
069 *        warningMessages     [1] SEQUENCE OF OCTET STRING OPTIONAL,
070 *        ... }
071 * </PRE>
072 *
073 * @see  IdentifyBackupCompatibilityProblemsExtendedRequest
074 * @see  GetBackupCompatibilityDescriptorExtendedRequest
075 */
076@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
077public final class IdentifyBackupCompatibilityProblemsExtendedResult
078       extends ExtendedResult
079{
080  /**
081   * The OID (1.3.6.1.4.1.30221.2.6.33) for the identify backup compatibility
082   * problems extended request.
083   */
084  public static final String IDENTIFY_BACKUP_COMPATIBILITY_PROBLEMS_RESULT_OID =
085       "1.3.6.1.4.1.30221.2.6.33";
086
087
088
089  /**
090   * The BER type for the error messages element in the value sequence.
091   */
092  private static final byte TYPE_ERRORS = (byte) 0xA0;
093
094
095
096  /**
097   * The BER type for the warning messages element in the value sequence.
098   */
099  private static final byte TYPE_WARNINGS = (byte) 0xA1;
100
101
102
103  /**
104   * The serial version UID for this serializable class.
105   */
106  private static final long serialVersionUID = -6492859100961846933L;
107
108
109
110  // The compatibility error messages.
111  private final List<String> errorMessages;
112
113  // The compatibility warning messages.
114  private final List<String> warningMessages;
115
116
117
118  /**
119   * Creates a new identify backup compatibility problems extended result from
120   * the provided generic extended result.
121   *
122   * @param  result  The generic extended result to be decoded as an identify
123   *                 backup compatibility problems extended result.
124   *
125   * @throws LDAPException  If the provided extended result cannot be parsed as
126   *                        a valid identify backup compatibility problems
127   *                        extended result.
128   */
129  public IdentifyBackupCompatibilityProblemsExtendedResult(
130              final ExtendedResult result)
131         throws LDAPException
132  {
133    super(result);
134
135    final ASN1OctetString value = result.getValue();
136    if (value == null)
137    {
138      errorMessages = Collections.emptyList();
139      warningMessages = Collections.emptyList();
140      return;
141    }
142
143    try
144    {
145      List<String> errors = Collections.emptyList();
146      List<String> warnings = Collections.emptyList();
147      final ASN1Element[] elements =
148           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
149      for (final ASN1Element e : elements)
150      {
151        switch (e.getType())
152        {
153          case TYPE_ERRORS:
154            final ASN1Element[] errorElements =
155                 ASN1Sequence.decodeAsSequence(e).elements();
156            final ArrayList<String> errorStrings =
157                 new ArrayList<String>(errorElements.length);
158            for (final ASN1Element errorElement : errorElements)
159            {
160              errorStrings.add(ASN1OctetString.decodeAsOctetString(
161                   errorElement).stringValue());
162            }
163            errors = Collections.unmodifiableList(errorStrings);
164            break;
165
166          case TYPE_WARNINGS:
167            final ASN1Element[] warningElements =
168                 ASN1Sequence.decodeAsSequence(e).elements();
169            final ArrayList<String> warningStrings =
170                 new ArrayList<String>(warningElements.length);
171            for (final ASN1Element warningElement : warningElements)
172            {
173              warningStrings.add(ASN1OctetString.decodeAsOctetString(
174                   warningElement).stringValue());
175            }
176            warnings = Collections.unmodifiableList(warningStrings);
177            break;
178
179          default:
180            throw new LDAPException(ResultCode.DECODING_ERROR,
181                 ERR_IDENTIFY_BACKUP_COMPAT_PROBLEMS_RESULT_UNEXPECTED_TYPE.get(
182                      StaticUtils.toHex(e.getType())));
183        }
184      }
185
186      errorMessages   = errors;
187      warningMessages = warnings;
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_BACKUP_COMPAT_RESULT_ERROR_PARSING_VALUE.get(
199                StaticUtils.getExceptionMessage(e)),
200           e);
201    }
202  }
203
204
205
206  /**
207   * Creates a new identify backup compatibility problems extended result with
208   * the provided 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  errorMessages      The set of error messages to include in the
219   *                            result.  It may be {@code null} or empty if no
220   *                            error messages should be included.
221   * @param  warningMessages    The set of warning messages to include in the
222   *                            result.  It may be {@code null} or empty if no
223   *                            warning messages should be included.
224   * @param  responseControls   The set of controls from the response, if
225   *                            available.
226   */
227  public IdentifyBackupCompatibilityProblemsExtendedResult(final int messageID,
228              final ResultCode resultCode, final String diagnosticMessage,
229              final String matchedDN, final String[] referralURLs,
230              final Collection<String> errorMessages,
231              final Collection<String> warningMessages,
232              final Control... responseControls)
233  {
234    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
235         ((resultCode == ResultCode.SUCCESS)
236              ? IDENTIFY_BACKUP_COMPATIBILITY_PROBLEMS_RESULT_OID
237              : null),
238         encodeValue(resultCode, errorMessages, warningMessages),
239         responseControls);
240
241    if (errorMessages == null)
242    {
243      this.errorMessages = Collections.emptyList();
244    }
245    else
246    {
247      this.errorMessages =
248           Collections.unmodifiableList(new ArrayList<String>(errorMessages));
249    }
250
251    if (warningMessages == null)
252    {
253      this.warningMessages = Collections.emptyList();
254    }
255    else
256    {
257      this.warningMessages =
258           Collections.unmodifiableList(new ArrayList<String>(warningMessages));
259    }
260  }
261
262
263
264  /**
265   * Creates an ASN.1 octet string containing an encoded representation of the
266   * value for an identify backup compatibility problems extended result with
267   * the provided information.
268   *
269   * @param  resultCode       The result code from the response.
270   * @param  errorMessages    The set of error messages to include in the
271   *                          result.  It may be {@code null} or empty if no
272   *                          error messages should be included.
273   * @param  warningMessages  The set of warning messages to include in the
274   *                          result.  It may be {@code null} or empty if no
275   *                          warning messages should be included.
276   *
277   * @return  An ASN.1 octet string containing an encoded representation of the
278   *          value for an identify backup compatibility problems extended
279   *          result, or {@code null} if a result with the provided information
280   *          should not have a value.
281   */
282  public static ASN1OctetString encodeValue(final ResultCode resultCode,
283                                     final Collection<String> errorMessages,
284                                     final Collection<String> warningMessages)
285  {
286    if (resultCode != ResultCode.SUCCESS)
287    {
288      Validator.ensureTrue(
289           (((errorMessages == null) || errorMessages.isEmpty()) &&
290            ((warningMessages == null) || warningMessages.isEmpty())),
291           "There must not be any warning or error messages with a " +
292                "non-success result.");
293      return null;
294    }
295
296    final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
297
298    if ((errorMessages != null) && (! errorMessages.isEmpty()))
299    {
300      final ArrayList<ASN1Element> msgElements =
301           new ArrayList<ASN1Element>(errorMessages.size());
302      for (final String s : errorMessages)
303      {
304        msgElements.add(new ASN1OctetString(s));
305      }
306      elements.add(new ASN1Sequence(TYPE_ERRORS, msgElements));
307    }
308
309    if ((warningMessages != null) && (! warningMessages.isEmpty()))
310    {
311      final ArrayList<ASN1Element> msgElements =
312           new ArrayList<ASN1Element>(warningMessages.size());
313      for (final String s : warningMessages)
314      {
315        msgElements.add(new ASN1OctetString(s));
316      }
317      elements.add(new ASN1Sequence(TYPE_WARNINGS, msgElements));
318    }
319
320    return new ASN1OctetString(new ASN1Sequence(elements).encode());
321  }
322
323
324
325  /**
326   * Retrieves a list of messages for any compatibility errors that have been
327   * identified.  If there are any errors, a backup from the source cannot be
328   * restored into the target.
329   *
330   * @return  A list of messages for any compatibility errors that have been
331   *          identified, or an empty list if there are no compatibility errors.
332   */
333  public List<String> getErrorMessages()
334  {
335    return errorMessages;
336  }
337
338
339
340  /**
341   * Retrieves a list of messages for any compatibility warnings that have been
342   * identified.  If there are any warnings, it may still be possible to restore
343   * a backup from the source into the target.
344   *
345   * @return  A list of messages for any compatibility warnings that have been
346   *          identified, or an empty list if there are no compatibility
347   *          warnings.
348   */
349  public List<String> getWarningMessages()
350  {
351    return warningMessages;
352  }
353
354
355
356  /**
357   * {@inheritDoc}
358   */
359  @Override()
360  public String getExtendedResultName()
361  {
362    return INFO_EXTENDED_RESULT_NAME_IDENTIFY_BACKUP_COMPAT_PROBLEMS.get();
363  }
364
365
366
367  /**
368   * {@inheritDoc}
369   */
370  @Override()
371  public void toString(final StringBuilder buffer)
372  {
373    buffer.append("IdentifyBackupCompatibilityProblemsExtendedResult(" +
374         "resultCode=");
375    buffer.append(getResultCode());
376
377    final int messageID = getMessageID();
378    if (messageID >= 0)
379    {
380      buffer.append(", messageID=");
381      buffer.append(messageID);
382    }
383
384    if (! errorMessages.isEmpty())
385    {
386      buffer.append(", errorMessages={");
387
388      final Iterator<String> iterator = errorMessages.iterator();
389      while (iterator.hasNext())
390      {
391        buffer.append('\'');
392        buffer.append(iterator.next());
393        buffer.append('\'');
394
395        if (iterator.hasNext())
396        {
397          buffer.append(',');
398        }
399      }
400
401      buffer.append('}');
402    }
403
404    if (! warningMessages.isEmpty())
405    {
406      buffer.append(", warningMessages={");
407
408      final Iterator<String> iterator = warningMessages.iterator();
409      while (iterator.hasNext())
410      {
411        buffer.append('\'');
412        buffer.append(iterator.next());
413        buffer.append('\'');
414
415        if (iterator.hasNext())
416        {
417          buffer.append(',');
418        }
419      }
420
421      buffer.append('}');
422    }
423
424    final String diagnosticMessage = getDiagnosticMessage();
425    if (diagnosticMessage != null)
426    {
427      buffer.append(", diagnosticMessage='");
428      buffer.append(diagnosticMessage);
429      buffer.append('\'');
430    }
431
432    final String matchedDN = getMatchedDN();
433    if (matchedDN != null)
434    {
435      buffer.append(", matchedDN='");
436      buffer.append(matchedDN);
437      buffer.append('\'');
438    }
439
440    final String[] referralURLs = getReferralURLs();
441    if (referralURLs.length > 0)
442    {
443      buffer.append(", referralURLs={");
444      for (int i=0; i < referralURLs.length; i++)
445      {
446        if (i > 0)
447        {
448          buffer.append(", ");
449        }
450
451        buffer.append('\'');
452        buffer.append(referralURLs[i]);
453        buffer.append('\'');
454      }
455      buffer.append('}');
456    }
457
458    final Control[] responseControls = getResponseControls();
459    if (responseControls.length > 0)
460    {
461      buffer.append(", responseControls={");
462      for (int i=0; i < responseControls.length; i++)
463      {
464        if (i > 0)
465        {
466          buffer.append(", ");
467        }
468
469        buffer.append(responseControls[i]);
470      }
471      buffer.append('}');
472    }
473
474    buffer.append(')');
475  }
476}