001/* 002 * Copyright 2009-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-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.protocol; 022 023 024 025import java.util.ArrayList; 026import java.util.Collections; 027import java.util.Iterator; 028import java.util.List; 029 030import com.unboundid.asn1.ASN1Buffer; 031import com.unboundid.asn1.ASN1BufferSequence; 032import com.unboundid.asn1.ASN1StreamReader; 033import com.unboundid.asn1.ASN1StreamReaderSequence; 034import com.unboundid.ldap.sdk.Control; 035import com.unboundid.ldap.sdk.LDAPException; 036import com.unboundid.ldap.sdk.LDAPResult; 037import com.unboundid.ldap.sdk.ResultCode; 038import com.unboundid.util.InternalUseOnly; 039import com.unboundid.util.NotExtensible; 040import com.unboundid.util.ThreadSafety; 041import com.unboundid.util.ThreadSafetyLevel; 042 043import static com.unboundid.ldap.protocol.ProtocolMessages.*; 044import static com.unboundid.util.Debug.*; 045import static com.unboundid.util.StaticUtils.*; 046import static com.unboundid.util.Validator.*; 047 048 049 050/** 051 * This class provides an implementation of a generic response protocol op. 052 * It must be subclassed by classes providing implementations for each 053 * operation type. 054 */ 055@InternalUseOnly() 056@NotExtensible() 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public abstract class GenericResponseProtocolOp 059 implements ProtocolOp 060{ 061 /** 062 * The BER type for the referral URLs elements. 063 */ 064 public static final byte TYPE_REFERRALS = (byte) 0xA3; 065 066 067 068 /** 069 * The serial version UID for this serializable class. 070 */ 071 private static final long serialVersionUID = 3837308973105414874L; 072 073 074 075 // The BER type for this response. 076 private final byte type; 077 078 // The result code for this response. 079 private final int resultCode; 080 081 // The referral URLs for this response. 082 private final List<String> referralURLs; 083 084 // The diagnostic message for this response. 085 private final String diagnosticMessage; 086 087 // The matched DN for this response.Static 088 private final String matchedDN; 089 090 091 092 /** 093 * Creates a new instance of this response with the provided information. 094 * 095 * @param type The BER type for this response. 096 * @param resultCode The result code for this response. 097 * @param matchedDN The matched DN for this result, if available. 098 * @param diagnosticMessage The diagnostic message for this response, if 099 * available. 100 * @param referralURLs The list of referral URLs for this response, if 101 * available. 102 */ 103 protected GenericResponseProtocolOp(final byte type, final int resultCode, 104 final String matchedDN, 105 final String diagnosticMessage, 106 final List<String> referralURLs) 107 { 108 this.type = type; 109 this.resultCode = resultCode; 110 this.matchedDN = matchedDN; 111 this.diagnosticMessage = diagnosticMessage; 112 113 if (referralURLs == null) 114 { 115 this.referralURLs = Collections.emptyList(); 116 } 117 else 118 { 119 this.referralURLs = Collections.unmodifiableList(referralURLs); 120 } 121 } 122 123 124 125 /** 126 * Creates a new response read from the provided ASN.1 stream reader. 127 * 128 * @param reader The ASN.1 stream reader from which to read the response. 129 * 130 * @throws LDAPException If a problem occurs while reading or parsing the 131 * response. 132 */ 133 protected GenericResponseProtocolOp(final ASN1StreamReader reader) 134 throws LDAPException 135 { 136 try 137 { 138 type = (byte) reader.peek(); 139 final ASN1StreamReaderSequence opSequence = reader.beginSequence(); 140 resultCode = reader.readEnumerated(); 141 142 String s = reader.readString(); 143 ensureNotNull(s); 144 if (s.length() == 0) 145 { 146 matchedDN = null; 147 } 148 else 149 { 150 matchedDN = s; 151 } 152 153 s = reader.readString(); 154 ensureNotNull(s); 155 if (s.length() == 0) 156 { 157 diagnosticMessage = null; 158 } 159 else 160 { 161 diagnosticMessage = s; 162 } 163 164 if (opSequence.hasMoreElements()) 165 { 166 final ArrayList<String> refs = new ArrayList<String>(1); 167 final ASN1StreamReaderSequence refSequence = reader.beginSequence(); 168 while (refSequence.hasMoreElements()) 169 { 170 refs.add(reader.readString()); 171 } 172 referralURLs = Collections.unmodifiableList(refs); 173 } 174 else 175 { 176 referralURLs = Collections.emptyList(); 177 } 178 } 179 catch (Exception e) 180 { 181 debugException(e); 182 throw new LDAPException(ResultCode.DECODING_ERROR, 183 ERR_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)), e); 184 } 185 } 186 187 188 189 /** 190 * Retrieves the result code for this response. 191 * 192 * @return The result code for this response. 193 */ 194 public final int getResultCode() 195 { 196 return resultCode; 197 } 198 199 200 201 /** 202 * Retrieves the matched DN for this response, if any. 203 * 204 * @return The matched DN for this response, or {@code null} if there is 205 * no matched DN. 206 */ 207 public final String getMatchedDN() 208 { 209 return matchedDN; 210 } 211 212 213 214 /** 215 * Retrieves the diagnostic message for this response, if any. 216 * 217 * @return The diagnostic message for this response, or {@code null} if there 218 * is no diagnostic message. 219 */ 220 public final String getDiagnosticMessage() 221 { 222 return diagnosticMessage; 223 } 224 225 226 227 /** 228 * Retrieves the list of referral URLs for this response. 229 * 230 * @return The list of referral URLs for this response, or an empty list 231 * if there are no referral URLs. 232 */ 233 public final List<String> getReferralURLs() 234 { 235 return referralURLs; 236 } 237 238 239 240 /** 241 * {@inheritDoc} 242 */ 243 public byte getProtocolOpType() 244 { 245 return type; 246 } 247 248 249 250 /** 251 * {@inheritDoc} 252 */ 253 public final void writeTo(final ASN1Buffer buffer) 254 { 255 final ASN1BufferSequence opSequence = buffer.beginSequence(type); 256 buffer.addEnumerated(resultCode); 257 buffer.addOctetString(matchedDN); 258 buffer.addOctetString(diagnosticMessage); 259 260 if (! referralURLs.isEmpty()) 261 { 262 final ASN1BufferSequence refSequence = 263 buffer.beginSequence(TYPE_REFERRALS); 264 for (final String s : referralURLs) 265 { 266 buffer.addOctetString(s); 267 } 268 refSequence.end(); 269 } 270 opSequence.end(); 271 } 272 273 274 275 /** 276 * Creates a new LDAP result object from this response protocol op. 277 * 278 * @param controls The set of controls to include in the LDAP result. It 279 * may be empty or {@code null} if no controls should be 280 * included. 281 * 282 * @return The LDAP result that was created. 283 */ 284 public LDAPResult toLDAPResult(final Control... controls) 285 { 286 final String[] refs; 287 if (referralURLs.isEmpty()) 288 { 289 refs = NO_STRINGS; 290 } 291 else 292 { 293 refs = new String[referralURLs.size()]; 294 referralURLs.toArray(refs); 295 } 296 297 return new LDAPResult(-1, ResultCode.valueOf(resultCode), diagnosticMessage, 298 matchedDN, refs, controls); 299 } 300 301 302 303 /** 304 * Retrieves a string representation of this protocol op. 305 * 306 * @return A string representation of this protocol op. 307 */ 308 @Override() 309 public final String toString() 310 { 311 final StringBuilder buffer = new StringBuilder(); 312 toString(buffer); 313 return buffer.toString(); 314 } 315 316 317 318 /** 319 * {@inheritDoc} 320 */ 321 public final void toString(final StringBuilder buffer) 322 { 323 buffer.append("ResponseProtocolOp(type="); 324 toHex(type, buffer); 325 buffer.append(", resultCode="); 326 buffer.append(resultCode); 327 328 if (matchedDN != null) 329 { 330 buffer.append(", matchedDN='"); 331 buffer.append(matchedDN); 332 buffer.append('\''); 333 } 334 335 if (diagnosticMessage != null) 336 { 337 buffer.append(", diagnosticMessage='"); 338 buffer.append(diagnosticMessage); 339 buffer.append('\''); 340 } 341 342 if (! referralURLs.isEmpty()) 343 { 344 buffer.append(", referralURLs={"); 345 346 final Iterator<String> iterator = referralURLs.iterator(); 347 while (iterator.hasNext()) 348 { 349 buffer.append('\''); 350 buffer.append(iterator.next()); 351 buffer.append('\''); 352 if (iterator.hasNext()) 353 { 354 buffer.append(','); 355 } 356 } 357 358 buffer.append('}'); 359 } 360 buffer.append(')'); 361 } 362}