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