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