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}