001/*
002 * Copyright 2009-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2009-2020 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2009-2020 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.protocol;
037
038
039
040import java.util.ArrayList;
041
042import com.unboundid.asn1.ASN1Buffer;
043import com.unboundid.asn1.ASN1BufferSequence;
044import com.unboundid.asn1.ASN1Element;
045import com.unboundid.asn1.ASN1OctetString;
046import com.unboundid.asn1.ASN1Sequence;
047import com.unboundid.asn1.ASN1StreamReader;
048import com.unboundid.asn1.ASN1StreamReaderSequence;
049import com.unboundid.ldap.sdk.Control;
050import com.unboundid.ldap.sdk.IntermediateResponse;
051import com.unboundid.ldap.sdk.LDAPException;
052import com.unboundid.ldap.sdk.ResultCode;
053import com.unboundid.util.Debug;
054import com.unboundid.util.InternalUseOnly;
055import com.unboundid.util.NotMutable;
056import com.unboundid.util.StaticUtils;
057import com.unboundid.util.ThreadSafety;
058import com.unboundid.util.ThreadSafetyLevel;
059
060import static com.unboundid.ldap.protocol.ProtocolMessages.*;
061
062
063
064/**
065 * This class provides an implementation of an LDAP intermediate response
066 * protocol op.
067 */
068@InternalUseOnly()
069@NotMutable()
070@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
071public final class IntermediateResponseProtocolOp
072       implements ProtocolOp
073{
074  /**
075   * The BER type for the OID element.
076   */
077  public static final byte TYPE_OID = (byte) 0x80;
078
079
080
081  /**
082   * The BER type for the value element.
083   */
084  public static final byte TYPE_VALUE = (byte) 0x81;
085
086
087
088  /**
089   * The serial version UID for this serializable class.
090   */
091  private static final long serialVersionUID = 118549806265654465L;
092
093
094
095  // The value for this intermediate response.
096  private final ASN1OctetString value;
097
098  // The OID for this intermediate response.
099  private final String oid;
100
101
102
103  /**
104   * Creates a new intermediate response protocol op with the provided
105   * information.
106   *
107   * @param  oid    The OID for this intermediate response, or {@code null} if
108   *                there should not be an OID.
109   * @param  value  The value for this intermediate response, or {@code null} if
110   *                there should not be a value.
111   */
112  public IntermediateResponseProtocolOp(final String oid,
113                                        final ASN1OctetString value)
114  {
115    this.oid = oid;
116
117    if (value == null)
118    {
119      this.value = null;
120    }
121    else
122    {
123      this.value = new ASN1OctetString(TYPE_VALUE, value.getValue());
124    }
125  }
126
127
128
129  /**
130   * Creates a new intermediate response protocol op from the provided
131   * intermediate response object.
132   *
133   * @param  response  The intermediate response object to use to create this
134   *                   protocol op.
135   */
136  public IntermediateResponseProtocolOp(final IntermediateResponse response)
137  {
138    oid = response.getOID();
139
140    final ASN1OctetString responseValue = response.getValue();
141    if (responseValue == null)
142    {
143      value = null;
144    }
145    else
146    {
147      value = new ASN1OctetString(TYPE_VALUE, responseValue.getValue());
148    }
149  }
150
151
152
153  /**
154   * Creates a new intermediate response protocol op read from the provided
155   * ASN.1 stream reader.
156   *
157   * @param  reader  The ASN.1 stream reader from which to read the intermediate
158   *                 response protocol op.
159   *
160   * @throws  LDAPException  If a problem occurs while reading or parsing the
161   *                         intermediate response.
162   */
163  IntermediateResponseProtocolOp(final ASN1StreamReader reader)
164       throws LDAPException
165  {
166    try
167    {
168      final ASN1StreamReaderSequence opSequence = reader.beginSequence();
169
170      String o = null;
171      ASN1OctetString v = null;
172      while (opSequence.hasMoreElements())
173      {
174        final byte type = (byte) reader.peek();
175        if (type == TYPE_OID)
176        {
177          o = reader.readString();
178        }
179        else if (type == TYPE_VALUE)
180        {
181          v = new ASN1OctetString(type, reader.readBytes());
182        }
183        else
184        {
185          throw new LDAPException(ResultCode.DECODING_ERROR,
186               ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(
187                    StaticUtils.toHex(type)));
188        }
189      }
190
191      oid = o;
192      value = v;
193    }
194    catch (final LDAPException le)
195    {
196      Debug.debugException(le);
197      throw le;
198    }
199    catch (final Exception e)
200    {
201      Debug.debugException(e);
202
203      throw new LDAPException(ResultCode.DECODING_ERROR,
204           ERR_INTERMEDIATE_RESPONSE_CANNOT_DECODE.get(
205                StaticUtils.getExceptionMessage(e)),
206           e);
207    }
208  }
209
210
211
212  /**
213   * Retrieves the OID for this intermediate response, if any.
214   *
215   * @return  The OID for this intermediate response, or {@code null} if there
216   *          is no response OID.
217   */
218  public String getOID()
219  {
220    return oid;
221  }
222
223
224
225  /**
226   * Retrieves the value for this intermediate response, if any.
227   *
228   * @return  The value for this intermediate response, or {@code null} if there
229   *          is no response value.
230   */
231  public ASN1OctetString getValue()
232  {
233    return value;
234  }
235
236
237
238  /**
239   * {@inheritDoc}
240   */
241  @Override()
242  public byte getProtocolOpType()
243  {
244    return LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE;
245  }
246
247
248
249  /**
250   * {@inheritDoc}
251   */
252  @Override()
253  public ASN1Element encodeProtocolOp()
254  {
255    final ArrayList<ASN1Element> elements = new ArrayList<>(2);
256
257    if (oid != null)
258    {
259      elements.add(new ASN1OctetString(TYPE_OID, oid));
260    }
261
262    if (value != null)
263    {
264      elements.add(value);
265    }
266
267    return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE,
268         elements);
269  }
270
271
272
273  /**
274   * Decodes the provided ASN.1 element as a intermediate response protocol op.
275   *
276   * @param  element  The ASN.1 element to be decoded.
277   *
278   * @return  The decoded intermediate response protocol op.
279   *
280   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
281   *                         a intermediate response protocol op.
282   */
283  public static IntermediateResponseProtocolOp decodeProtocolOp(
284                                                    final ASN1Element element)
285         throws LDAPException
286  {
287    try
288    {
289      String oid = null;
290      ASN1OctetString value = null;
291      for (final ASN1Element e :
292           ASN1Sequence.decodeAsSequence(element).elements())
293      {
294        switch (e.getType())
295        {
296          case TYPE_OID:
297            oid = ASN1OctetString.decodeAsOctetString(e).stringValue();
298            break;
299          case TYPE_VALUE:
300            value = ASN1OctetString.decodeAsOctetString(e);
301            break;
302          default:
303            throw new LDAPException(ResultCode.DECODING_ERROR,
304                 ERR_INTERMEDIATE_RESPONSE_INVALID_ELEMENT.get(
305                      StaticUtils.toHex(e.getType())));
306        }
307      }
308
309      return new IntermediateResponseProtocolOp(oid, value);
310    }
311    catch (final LDAPException le)
312    {
313      Debug.debugException(le);
314      throw le;
315    }
316    catch (final Exception e)
317    {
318      Debug.debugException(e);
319      throw new LDAPException(ResultCode.DECODING_ERROR,
320           ERR_COMPARE_REQUEST_CANNOT_DECODE.get(
321                StaticUtils.getExceptionMessage(e)),
322           e);
323    }
324  }
325
326
327
328  /**
329   * {@inheritDoc}
330   */
331  @Override()
332  public void writeTo(final ASN1Buffer buffer)
333  {
334    final ASN1BufferSequence opSequence = buffer.beginSequence(
335         LDAPMessage.PROTOCOL_OP_TYPE_INTERMEDIATE_RESPONSE);
336
337    if (oid != null)
338    {
339      buffer.addOctetString(TYPE_OID, oid);
340    }
341
342    if (value != null)
343    {
344      buffer.addElement(value);
345    }
346
347    opSequence.end();
348  }
349
350
351
352  /**
353   * Creates a intermediate response from this protocol op.
354   *
355   * @param  controls  The set of controls to include in the intermediate
356   *                   response.  It may be empty or {@code null} if no controls
357   *                   should be included.
358   *
359   * @return  The intermediate response that was created.
360   */
361  public IntermediateResponse toIntermediateResponse(final Control... controls)
362  {
363    return new IntermediateResponse(-1, oid, value, controls);
364  }
365
366
367
368  /**
369   * Retrieves a string representation of this protocol op.
370   *
371   * @return  A string representation of this protocol op.
372   */
373  @Override()
374  public String toString()
375  {
376    final StringBuilder buffer = new StringBuilder();
377    toString(buffer);
378    return buffer.toString();
379  }
380
381
382
383  /**
384   * {@inheritDoc}
385   */
386  @Override()
387  public void toString(final StringBuilder buffer)
388  {
389    buffer.append("IntermediateResponseProtocolOp(");
390
391    if (oid != null)
392    {
393      buffer.append("oid='");
394      buffer.append(oid);
395      buffer.append('\'');
396    }
397
398    buffer.append(')');
399  }
400}