001/*
002 * Copyright 2009-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-2019 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}