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}