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