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}