001/* 002 * Copyright 2009-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2017 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; 026 027import com.unboundid.asn1.ASN1Buffer; 028import com.unboundid.asn1.ASN1BufferSequence; 029import com.unboundid.asn1.ASN1Element; 030import com.unboundid.asn1.ASN1OctetString; 031import com.unboundid.asn1.ASN1Sequence; 032import com.unboundid.asn1.ASN1StreamReader; 033import com.unboundid.asn1.ASN1StreamReaderSequence; 034import com.unboundid.ldap.sdk.Control; 035import com.unboundid.ldap.sdk.IntermediateResponse; 036import com.unboundid.ldap.sdk.LDAPException; 037import com.unboundid.ldap.sdk.ResultCode; 038import com.unboundid.util.NotMutable; 039import com.unboundid.util.InternalUseOnly; 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.*; 046 047 048 049/** 050 * This class provides an implementation of an LDAP intermediate response 051 * protocol op. 052 */ 053@InternalUseOnly() 054@NotMutable() 055@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 056public final class IntermediateResponseProtocolOp 057 implements ProtocolOp 058{ 059 /** 060 * The BER type for the OID element. 061 */ 062 public static final byte TYPE_OID = (byte) 0x80; 063 064 065 066 /** 067 * The BER type for the value element. 068 */ 069 public static final byte TYPE_VALUE = (byte) 0x81; 070 071 072 073 /** 074 * The serial version UID for this serializable class. 075 */ 076 private static final long serialVersionUID = 118549806265654465L; 077 078 079 080 // The value for this intermediate response. 081 private final ASN1OctetString value; 082 083 // The OID for this intermediate response. 084 private final String oid; 085 086 087 088 /** 089 * Creates a new intermediate response protocol op with the provided 090 * information. 091 * 092 * @param oid The OID for this intermediate response, or {@code null} if 093 * there should not be an OID. 094 * @param value The value for this intermediate response, or {@code null} if 095 * there should not be a value. 096 */ 097 public IntermediateResponseProtocolOp(final String oid, 098 final ASN1OctetString value) 099 { 100 this.oid = oid; 101 102 if (value == null) 103 { 104 this.value = null; 105 } 106 else 107 { 108 this.value = new ASN1OctetString(TYPE_VALUE, value.getValue()); 109 } 110 } 111 112 113 114 /** 115 * Creates a new intermediate response protocol op from the provided 116 * intermediate response object. 117 * 118 * @param response The intermediate response object to use to create this 119 * protocol op. 120 */ 121 public IntermediateResponseProtocolOp(final IntermediateResponse response) 122 { 123 oid = response.getOID(); 124 125 final ASN1OctetString responseValue = response.getValue(); 126 if (responseValue == null) 127 { 128 value = null; 129 } 130 else 131 { 132 value = new ASN1OctetString(TYPE_VALUE, responseValue.getValue()); 133 } 134 } 135 136 137 138 /** 139 * Creates a new intermediate response protocol op read from the provided 140 * ASN.1 stream reader. 141 * 142 * @param reader The ASN.1 stream reader from which to read the intermediate 143 * response protocol op. 144 * 145 * @throws LDAPException If a problem occurs while reading or parsing the 146 * intermediate response. 147 */ 148 IntermediateResponseProtocolOp(final ASN1StreamReader reader) 149 throws LDAPException 150 { 151 try 152 { 153 final ASN1StreamReaderSequence opSequence = reader.beginSequence(); 154 155 String o = null; 156 ASN1OctetString v = null; 157 while (opSequence.hasMoreElements()) 158 { 159 final byte type = (byte) reader.peek(); 160 if (type == TYPE_OID) 161 { 162 o = reader.readString(); 163 } 164 else if (type == TYPE_VALUE) 165 { 166 v = new ASN1OctetString(type, reader.readBytes()); 167 } 168 else 169 { 170 throw new LDAPException(ResultCode.DECODING_ERROR, 171 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(toHex(type))); 172 } 173 } 174 175 oid = o; 176 value = v; 177 } 178 catch (LDAPException le) 179 { 180 debugException(le); 181 throw le; 182 } 183 catch (Exception e) 184 { 185 debugException(e); 186 187 throw new LDAPException(ResultCode.DECODING_ERROR, 188 ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get(getExceptionMessage(e)), 189 e); 190 } 191 } 192 193 194 195 /** 196 * Retrieves the OID for this intermediate response, if any. 197 * 198 * @return The OID for this intermediate response, or {@code null} if there 199 * is no response OID. 200 */ 201 public String getOID() 202 { 203 return oid; 204 } 205 206 207 208 /** 209 * Retrieves the value for this intermediate response, if any. 210 * 211 * @return The value for this intermediate response, or {@code null} if there 212 * is no response value. 213 */ 214 public ASN1OctetString getValue() 215 { 216 return value; 217 } 218 219 220 221 /** 222 * {@inheritDoc} 223 */ 224 public byte getProtocolOpType() 225 { 226 return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE; 227 } 228 229 230 231 /** 232 * {@inheritDoc} 233 */ 234 public ASN1Element encodeProtocolOp() 235 { 236 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); 237 238 if (oid != null) 239 { 240 elements.add(new ASN1OctetString(TYPE_OID, oid)); 241 } 242 243 if (value != null) 244 { 245 elements.add(value); 246 } 247 248 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE, 249 elements); 250 } 251 252 253 254 /** 255 * Decodes the provided ASN.1 element as a intermediate response protocol op. 256 * 257 * @param element The ASN.1 element to be decoded. 258 * 259 * @return The decoded intermediate response protocol op. 260 * 261 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 262 * a intermediate response protocol op. 263 */ 264 public static IntermediateResponseProtocolOp decodeProtocolOp( 265 final ASN1Element element) 266 throws LDAPException 267 { 268 try 269 { 270 String oid = null; 271 ASN1OctetString value = null; 272 for (final ASN1Element e : 273 ASN1Sequence.decodeAsSequence(element).elements()) 274 { 275 switch (e.getType()) 276 { 277 case TYPE_OID: 278 oid = ASN1OctetString.decodeAsOctetString(e).stringValue(); 279 break; 280 case TYPE_VALUE: 281 value = ASN1OctetString.decodeAsOctetString(e); 282 break; 283 default: 284 throw new LDAPException(ResultCode.DECODING_ERROR, 285 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get( 286 toHex(e.getType()))); 287 } 288 } 289 290 return new IntermediateResponseProtocolOp(oid, value); 291 } 292 catch (final LDAPException le) 293 { 294 debugException(le); 295 throw le; 296 } 297 catch (final Exception e) 298 { 299 debugException(e); 300 throw new LDAPException(ResultCode.DECODING_ERROR, 301 ERR_COMPARE_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), 302 e); 303 } 304 } 305 306 307 308 /** 309 * {@inheritDoc} 310 */ 311 public void writeTo(final ASN1Buffer buffer) 312 { 313 final ASN1BufferSequence opSequence = buffer.beginSequence( 314 LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE); 315 316 if (oid != null) 317 { 318 buffer.addOctetString(TYPE_OID, oid); 319 } 320 321 if (value != null) 322 { 323 buffer.addElement(value); 324 } 325 326 opSequence.end(); 327 } 328 329 330 331 /** 332 * Creates a intermediate response from this protocol op. 333 * 334 * @param controls The set of controls to include in the intermediate 335 * response. It may be empty or {@code null} if no controls 336 * should be included. 337 * 338 * @return The intermediate response that was created. 339 */ 340 public IntermediateResponse toIntermediateResponse(final Control... controls) 341 { 342 return new IntermediateResponse(-1, oid, value, controls); 343 } 344 345 346 347 /** 348 * Retrieves a string representation of this protocol op. 349 * 350 * @return A string representation of this protocol op. 351 */ 352 @Override() 353 public String toString() 354 { 355 final StringBuilder buffer = new StringBuilder(); 356 toString(buffer); 357 return buffer.toString(); 358 } 359 360 361 362 /** 363 * {@inheritDoc} 364 */ 365 public void toString(final StringBuilder buffer) 366 { 367 buffer.append("IntermediateResponseProtocolOp("); 368 369 if (oid != null) 370 { 371 buffer.append("oid='"); 372 buffer.append(oid); 373 buffer.append('\''); 374 } 375 376 buffer.append(')'); 377 } 378}