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