001/* 002 * Copyright 2009-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2018 Ping Identity Corporation 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.Debug; 039import com.unboundid.util.InternalUseOnly; 040import com.unboundid.util.NotMutable; 041import com.unboundid.util.StaticUtils; 042import com.unboundid.util.ThreadSafety; 043import com.unboundid.util.ThreadSafetyLevel; 044 045import static com.unboundid.ldap.protocol.ProtocolMessages.*; 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( 172 StaticUtils.toHex(type))); 173 } 174 } 175 176 oid = o; 177 value = v; 178 } 179 catch (final LDAPException le) 180 { 181 Debug.debugException(le); 182 throw le; 183 } 184 catch (final Exception e) 185 { 186 Debug.debugException(e); 187 188 throw new LDAPException(ResultCode.DECODING_ERROR, 189 ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get( 190 StaticUtils.getExceptionMessage(e)), 191 e); 192 } 193 } 194 195 196 197 /** 198 * Retrieves the OID for this intermediate response, if any. 199 * 200 * @return The OID for this intermediate response, or {@code null} if there 201 * is no response OID. 202 */ 203 public String getOID() 204 { 205 return oid; 206 } 207 208 209 210 /** 211 * Retrieves the value for this intermediate response, if any. 212 * 213 * @return The value for this intermediate response, or {@code null} if there 214 * is no response value. 215 */ 216 public ASN1OctetString getValue() 217 { 218 return value; 219 } 220 221 222 223 /** 224 * {@inheritDoc} 225 */ 226 @Override() 227 public byte getProtocolOpType() 228 { 229 return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE; 230 } 231 232 233 234 /** 235 * {@inheritDoc} 236 */ 237 @Override() 238 public ASN1Element encodeProtocolOp() 239 { 240 final ArrayList<ASN1Element> elements = new ArrayList<>(2); 241 242 if (oid != null) 243 { 244 elements.add(new ASN1OctetString(TYPE_OID, oid)); 245 } 246 247 if (value != null) 248 { 249 elements.add(value); 250 } 251 252 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE, 253 elements); 254 } 255 256 257 258 /** 259 * Decodes the provided ASN.1 element as a intermediate response protocol op. 260 * 261 * @param element The ASN.1 element to be decoded. 262 * 263 * @return The decoded intermediate response protocol op. 264 * 265 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 266 * a intermediate response protocol op. 267 */ 268 public static IntermediateResponseProtocolOp decodeProtocolOp( 269 final ASN1Element element) 270 throws LDAPException 271 { 272 try 273 { 274 String oid = null; 275 ASN1OctetString value = null; 276 for (final ASN1Element e : 277 ASN1Sequence.decodeAsSequence(element).elements()) 278 { 279 switch (e.getType()) 280 { 281 case TYPE_OID: 282 oid = ASN1OctetString.decodeAsOctetString(e).stringValue(); 283 break; 284 case TYPE_VALUE: 285 value = ASN1OctetString.decodeAsOctetString(e); 286 break; 287 default: 288 throw new LDAPException(ResultCode.DECODING_ERROR, 289 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get( 290 StaticUtils.toHex(e.getType()))); 291 } 292 } 293 294 return new IntermediateResponseProtocolOp(oid, value); 295 } 296 catch (final LDAPException le) 297 { 298 Debug.debugException(le); 299 throw le; 300 } 301 catch (final Exception e) 302 { 303 Debug.debugException(e); 304 throw new LDAPException(ResultCode.DECODING_ERROR, 305 ERR_COMPARE_REQUEST_CANNOT_DECODE.get( 306 StaticUtils.getExceptionMessage(e)), 307 e); 308 } 309 } 310 311 312 313 /** 314 * {@inheritDoc} 315 */ 316 @Override() 317 public void writeTo(final ASN1Buffer buffer) 318 { 319 final ASN1BufferSequence opSequence = buffer.beginSequence( 320 LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE); 321 322 if (oid != null) 323 { 324 buffer.addOctetString(TYPE_OID, oid); 325 } 326 327 if (value != null) 328 { 329 buffer.addElement(value); 330 } 331 332 opSequence.end(); 333 } 334 335 336 337 /** 338 * Creates a intermediate response from this protocol op. 339 * 340 * @param controls The set of controls to include in the intermediate 341 * response. It may be empty or {@code null} if no controls 342 * should be included. 343 * 344 * @return The intermediate response that was created. 345 */ 346 public IntermediateResponse toIntermediateResponse(final Control... controls) 347 { 348 return new IntermediateResponse(-1, oid, value, controls); 349 } 350 351 352 353 /** 354 * Retrieves a string representation of this protocol op. 355 * 356 * @return A string representation of this protocol op. 357 */ 358 @Override() 359 public String toString() 360 { 361 final StringBuilder buffer = new StringBuilder(); 362 toString(buffer); 363 return buffer.toString(); 364 } 365 366 367 368 /** 369 * {@inheritDoc} 370 */ 371 @Override() 372 public void toString(final StringBuilder buffer) 373 { 374 buffer.append("IntermediateResponseProtocolOp("); 375 376 if (oid != null) 377 { 378 buffer.append("oid='"); 379 buffer.append(oid); 380 buffer.append('\''); 381 } 382 383 buffer.append(')'); 384 } 385}