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}