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.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 (final LDAPException le) 179 { 180 debugException(le); 181 throw le; 182 } 183 catch (final 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 @Override() 225 public byte getProtocolOpType() 226 { 227 return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE; 228 } 229 230 231 232 /** 233 * {@inheritDoc} 234 */ 235 @Override() 236 public ASN1Element encodeProtocolOp() 237 { 238 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); 239 240 if (oid != null) 241 { 242 elements.add(new ASN1OctetString(TYPE_OID, oid)); 243 } 244 245 if (value != null) 246 { 247 elements.add(value); 248 } 249 250 return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE, 251 elements); 252 } 253 254 255 256 /** 257 * Decodes the provided ASN.1 element as a intermediate response protocol op. 258 * 259 * @param element The ASN.1 element to be decoded. 260 * 261 * @return The decoded intermediate response protocol op. 262 * 263 * @throws LDAPException If the provided ASN.1 element cannot be decoded as 264 * a intermediate response protocol op. 265 */ 266 public static IntermediateResponseProtocolOp decodeProtocolOp( 267 final ASN1Element element) 268 throws LDAPException 269 { 270 try 271 { 272 String oid = null; 273 ASN1OctetString value = null; 274 for (final ASN1Element e : 275 ASN1Sequence.decodeAsSequence(element).elements()) 276 { 277 switch (e.getType()) 278 { 279 case TYPE_OID: 280 oid = ASN1OctetString.decodeAsOctetString(e).stringValue(); 281 break; 282 case TYPE_VALUE: 283 value = ASN1OctetString.decodeAsOctetString(e); 284 break; 285 default: 286 throw new LDAPException(ResultCode.DECODING_ERROR, 287 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get( 288 toHex(e.getType()))); 289 } 290 } 291 292 return new IntermediateResponseProtocolOp(oid, value); 293 } 294 catch (final LDAPException le) 295 { 296 debugException(le); 297 throw le; 298 } 299 catch (final Exception e) 300 { 301 debugException(e); 302 throw new LDAPException(ResultCode.DECODING_ERROR, 303 ERR_COMPARE_REQUEST_CANNOT_DECODE.get(getExceptionMessage(e)), 304 e); 305 } 306 } 307 308 309 310 /** 311 * {@inheritDoc} 312 */ 313 @Override() 314 public void writeTo(final ASN1Buffer buffer) 315 { 316 final ASN1BufferSequence opSequence = buffer.beginSequence( 317 LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE); 318 319 if (oid != null) 320 { 321 buffer.addOctetString(TYPE_OID, oid); 322 } 323 324 if (value != null) 325 { 326 buffer.addElement(value); 327 } 328 329 opSequence.end(); 330 } 331 332 333 334 /** 335 * Creates a intermediate response from this protocol op. 336 * 337 * @param controls The set of controls to include in the intermediate 338 * response. It may be empty or {@code null} if no controls 339 * should be included. 340 * 341 * @return The intermediate response that was created. 342 */ 343 public IntermediateResponse toIntermediateResponse(final Control... controls) 344 { 345 return new IntermediateResponse(-1, oid, value, controls); 346 } 347 348 349 350 /** 351 * Retrieves a string representation of this protocol op. 352 * 353 * @return A string representation of this protocol op. 354 */ 355 @Override() 356 public String toString() 357 { 358 final StringBuilder buffer = new StringBuilder(); 359 toString(buffer); 360 return buffer.toString(); 361 } 362 363 364 365 /** 366 * {@inheritDoc} 367 */ 368 @Override() 369 public void toString(final StringBuilder buffer) 370 { 371 buffer.append("IntermediateResponseProtocolOp("); 372 373 if (oid != null) 374 { 375 buffer.append("oid='"); 376 buffer.append(oid); 377 buffer.append('\''); 378 } 379 380 buffer.append(')'); 381 } 382}