001/* 002 * Copyright 2007-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2014 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 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import java.util.ArrayList; 026 027import com.unboundid.asn1.ASN1OctetString; 028import com.unboundid.asn1.ASN1StreamReader; 029import com.unboundid.asn1.ASN1StreamReaderSequence; 030import com.unboundid.util.Extensible; 031import com.unboundid.util.NotMutable; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.ldap.sdk.LDAPMessages.*; 036import static com.unboundid.util.Debug.*; 037import static com.unboundid.util.StaticUtils.*; 038 039 040 041/** 042 * This class provides a data structure for holding information about the result 043 * of processing an extended operation. It includes all of the generic LDAP 044 * result elements as described in the {@link LDAPResult} class, but it may also 045 * include the following elements: 046 * <UL> 047 * <LI>Response OID -- An optional OID that can be used to identify the type 048 * of response. This may be used if there can be different types of 049 * responses for a given request.</LI> 050 * <LI>Value -- An optional element that provides the encoded value for this 051 * response. If a value is provided, then the encoding for the value 052 * depends on the type of extended result.</LI> 053 * </UL> 054 */ 055@Extensible() 056@NotMutable() 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public class ExtendedResult 059 extends LDAPResult 060{ 061 /** 062 * The BER type for the extended response OID element. 063 */ 064 private static final byte TYPE_EXTENDED_RESPONSE_OID = (byte) 0x8A; 065 066 067 068 /** 069 * The BER type for the extended response value element. 070 */ 071 private static final byte TYPE_EXTENDED_RESPONSE_VALUE = (byte) 0x8B; 072 073 074 075 /** 076 * The serial version UID for this serializable class. 077 */ 078 private static final long serialVersionUID = -6885923482396647963L; 079 080 081 082 // The encoded value for this extended response, if available. 083 private final ASN1OctetString value; 084 085 // The OID for this extended response, if available. 086 private final String oid; 087 088 089 090 /** 091 * Creates a new extended result with the provided information. 092 * 093 * @param messageID The message ID for the LDAP message that is 094 * associated with this LDAP result. 095 * @param resultCode The result code from the response. 096 * @param diagnosticMessage The diagnostic message from the response, if 097 * available. 098 * @param matchedDN The matched DN from the response, if available. 099 * @param referralURLs The set of referral URLs from the response, if 100 * available. 101 * @param oid The OID for this extended response, if 102 * available. 103 * @param value The encoded value for this extended response, if 104 * available. 105 * @param responseControls The set of controls from the response, if 106 * available. 107 */ 108 public ExtendedResult(final int messageID, final ResultCode resultCode, 109 final String diagnosticMessage, final String matchedDN, 110 final String[] referralURLs, final String oid, 111 final ASN1OctetString value, 112 final Control[] responseControls) 113 { 114 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 115 responseControls); 116 117 this.oid = oid; 118 this.value = value; 119 } 120 121 122 123 /** 124 * Creates a new extended result with the information contained in the 125 * provided LDAP result. The extended result will not have an OID or value. 126 * 127 * @param result The LDAP result whose content should be used for this 128 * extended result. 129 */ 130 public ExtendedResult(final LDAPResult result) 131 { 132 super(result); 133 134 oid = null; 135 value = null; 136 } 137 138 139 140 /** 141 * Creates a new extended result from the provided {@code LDAPException}. 142 * The extended result will not have an OID or value. 143 * 144 * @param exception The {@code LDAPException} to use to create this extended 145 * result. 146 */ 147 public ExtendedResult(final LDAPException exception) 148 { 149 this(exception.toLDAPResult()); 150 } 151 152 153 154 /** 155 * Creates a new extended result initialized from all of the elements of the 156 * provided extended response. 157 * 158 * @param extendedResult The extended response to use to initialize this 159 * extended response. 160 */ 161 protected ExtendedResult(final ExtendedResult extendedResult) 162 { 163 this(extendedResult.getMessageID(), extendedResult.getResultCode(), 164 extendedResult.getDiagnosticMessage(), extendedResult.getMatchedDN(), 165 extendedResult.getReferralURLs(), extendedResult.getOID(), 166 extendedResult.getValue(), extendedResult.getResponseControls()); 167 } 168 169 170 171 /** 172 * Creates a new extended result object with the provided message ID and with 173 * the protocol op and controls read from the given ASN.1 stream reader. 174 * 175 * @param messageID The LDAP message ID for the LDAP message that is 176 * associated with this extended result. 177 * @param messageSequence The ASN.1 stream reader sequence used in the 178 * course of reading the LDAP message elements. 179 * @param reader The ASN.1 stream reader from which to read the 180 * protocol op and controls. 181 * 182 * @return The decoded extended result. 183 * 184 * @throws LDAPException If a problem occurs while reading or decoding data 185 * from the ASN.1 stream reader. 186 */ 187 static ExtendedResult readExtendedResultFrom(final int messageID, 188 final ASN1StreamReaderSequence messageSequence, 189 final ASN1StreamReader reader) 190 throws LDAPException 191 { 192 try 193 { 194 final ASN1StreamReaderSequence protocolOpSequence = 195 reader.beginSequence(); 196 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 197 198 String matchedDN = reader.readString(); 199 if (matchedDN.length() == 0) 200 { 201 matchedDN = null; 202 } 203 204 String diagnosticMessage = reader.readString(); 205 if (diagnosticMessage.length() == 0) 206 { 207 diagnosticMessage = null; 208 } 209 210 String[] referralURLs = null; 211 String oid = null; 212 ASN1OctetString value = null; 213 while (protocolOpSequence.hasMoreElements()) 214 { 215 final byte type = (byte) reader.peek(); 216 switch (type) 217 { 218 case TYPE_REFERRAL_URLS: 219 final ArrayList<String> refList = new ArrayList<String>(1); 220 final ASN1StreamReaderSequence refSequence = reader.beginSequence(); 221 while (refSequence.hasMoreElements()) 222 { 223 refList.add(reader.readString()); 224 } 225 referralURLs = new String[refList.size()]; 226 refList.toArray(referralURLs); 227 break; 228 229 case TYPE_EXTENDED_RESPONSE_OID: 230 oid = reader.readString(); 231 break; 232 233 case TYPE_EXTENDED_RESPONSE_VALUE: 234 value = new ASN1OctetString(type, reader.readBytes()); 235 break; 236 237 default: 238 throw new LDAPException(ResultCode.DECODING_ERROR, 239 ERR_EXTENDED_RESULT_INVALID_ELEMENT.get(toHex(type))); 240 } 241 } 242 243 Control[] controls = NO_CONTROLS; 244 if (messageSequence.hasMoreElements()) 245 { 246 final ArrayList<Control> controlList = new ArrayList<Control>(1); 247 final ASN1StreamReaderSequence controlSequence = reader.beginSequence(); 248 while (controlSequence.hasMoreElements()) 249 { 250 controlList.add(Control.readFrom(reader)); 251 } 252 253 controls = new Control[controlList.size()]; 254 controlList.toArray(controls); 255 } 256 257 return new ExtendedResult(messageID, resultCode, diagnosticMessage, 258 matchedDN, referralURLs, oid, value, controls); 259 } 260 catch (LDAPException le) 261 { 262 debugException(le); 263 throw le; 264 } 265 catch (Exception e) 266 { 267 debugException(e); 268 throw new LDAPException(ResultCode.DECODING_ERROR, 269 ERR_EXTENDED_RESULT_CANNOT_DECODE.get(getExceptionMessage(e)), e); 270 } 271 } 272 273 274 275 /** 276 * Retrieves the OID for this extended result, if available. 277 * 278 * @return The OID for this extended result, or {@code null} if none is 279 * available. 280 */ 281 public final String getOID() 282 { 283 return oid; 284 } 285 286 287 288 /** 289 * Indicates whether this extended result has a value. 290 * 291 * @return {@code true} if this extended result has a value, or 292 * {@code false} if not. 293 */ 294 public final boolean hasValue() 295 { 296 return (value != null); 297 } 298 299 300 301 /** 302 * Retrieves the encoded value for this extended result, if available. 303 * 304 * @return The encoded value for this extended result, or {@code null} if 305 * none is available. 306 */ 307 public final ASN1OctetString getValue() 308 { 309 return value; 310 } 311 312 313 314 /** 315 * Retrieves the user-friendly name for the extended result, if available. 316 * If no user-friendly name has been defined, but a response OID is available, 317 * then that will be returned. If neither a user-friendly name nor a response 318 * OID are available, then {@code null} will be returned. 319 * 320 * @return The user-friendly name for this extended request, the response OID 321 * if a user-friendly name is not available but a response OID is, or 322 * {@code null} if neither a user-friendly name nor a response OID 323 * are available. 324 */ 325 public String getExtendedResultName() 326 { 327 // By default, we will return the OID (which may be null). Subclasses 328 // should override this to provide the user-friendly name. 329 return oid; 330 } 331 332 333 334 /** 335 * Retrieves a string representation of this extended response. 336 * 337 * @return A string representation of this extended response. 338 */ 339 @Override() 340 public String toString() 341 { 342 final StringBuilder buffer = new StringBuilder(); 343 toString(buffer); 344 return buffer.toString(); 345 } 346 347 348 349 /** 350 * Appends a string representation of this extended response to the provided 351 * buffer. 352 * 353 * @param buffer The buffer to which a string representation of this 354 * extended response will be appended. 355 */ 356 @Override() 357 public void toString(final StringBuilder buffer) 358 { 359 buffer.append("ExtendedResult(resultCode="); 360 buffer.append(getResultCode()); 361 362 final int messageID = getMessageID(); 363 if (messageID >= 0) 364 { 365 buffer.append(", messageID="); 366 buffer.append(messageID); 367 } 368 369 final String diagnosticMessage = getDiagnosticMessage(); 370 if (diagnosticMessage != null) 371 { 372 buffer.append(", diagnosticMessage='"); 373 buffer.append(diagnosticMessage); 374 buffer.append('\''); 375 } 376 377 final String matchedDN = getMatchedDN(); 378 if (matchedDN != null) 379 { 380 buffer.append(", matchedDN='"); 381 buffer.append(matchedDN); 382 buffer.append('\''); 383 } 384 385 final String[] referralURLs = getReferralURLs(); 386 if (referralURLs.length > 0) 387 { 388 buffer.append(", referralURLs={"); 389 for (int i=0; i < referralURLs.length; i++) 390 { 391 if (i > 0) 392 { 393 buffer.append(", "); 394 } 395 396 buffer.append(referralURLs[i]); 397 } 398 buffer.append('}'); 399 } 400 401 if (oid != null) 402 { 403 buffer.append(", oid="); 404 buffer.append(oid); 405 } 406 407 final Control[] responseControls = getResponseControls(); 408 if (responseControls.length > 0) 409 { 410 buffer.append(", responseControls={"); 411 for (int i=0; i < responseControls.length; i++) 412 { 413 if (i > 0) 414 { 415 buffer.append(", "); 416 } 417 418 buffer.append(responseControls[i]); 419 } 420 buffer.append('}'); 421 } 422 423 buffer.append(')'); 424 } 425}