001/*
002 * Copyright 2009-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2009-2024 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-2024 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 com.unboundid.asn1.ASN1Buffer;
041import com.unboundid.asn1.ASN1BufferSequence;
042import com.unboundid.asn1.ASN1Element;
043import com.unboundid.asn1.ASN1OctetString;
044import com.unboundid.asn1.ASN1Sequence;
045import com.unboundid.asn1.ASN1StreamReader;
046import com.unboundid.asn1.ASN1StreamReaderSequence;
047import com.unboundid.ldap.sdk.Control;
048import com.unboundid.ldap.sdk.ExtendedRequest;
049import com.unboundid.ldap.sdk.LDAPException;
050import com.unboundid.ldap.sdk.ResultCode;
051import com.unboundid.util.Debug;
052import com.unboundid.util.InternalUseOnly;
053import com.unboundid.util.NotMutable;
054import com.unboundid.util.NotNull;
055import com.unboundid.util.Nullable;
056import com.unboundid.util.StaticUtils;
057import com.unboundid.util.ThreadSafety;
058import com.unboundid.util.ThreadSafetyLevel;
059import com.unboundid.util.Validator;
060
061import static com.unboundid.ldap.protocol.ProtocolMessages.*;
062
063
064
065/**
066 * This class provides an implementation of an LDAP extended request protocol
067 * op.
068 */
069@InternalUseOnly()
070@NotMutable()
071@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
072public final class ExtendedRequestProtocolOp
073       implements ProtocolOp
074{
075  /**
076   * The BER type for the OID element.
077   */
078  public static final byte TYPE_OID = (byte) 0x80;
079
080
081
082  /**
083   * The BER type for the value element.
084   */
085  public static final byte TYPE_VALUE = (byte) 0x81;
086
087
088
089  /**
090   * The serial version UID for this serializable class.
091   */
092  private static final long serialVersionUID = -5343424210200494377L;
093
094
095
096  // The value for this extended request.
097  @Nullable private final ASN1OctetString value;
098
099  // The OID for this extended request.
100  @NotNull private final String oid;
101
102
103
104  /**
105   * Creates a new extended request protocol op with the provided information.
106   *
107   * @param  oid    The OID for this extended request.
108   * @param  value  The value for this extended request, or {@code null} if
109   *                there should not be a value.
110   */
111  public ExtendedRequestProtocolOp(@NotNull final String oid,
112                                   @Nullable final ASN1OctetString value)
113  {
114    this.oid = oid;
115
116    if (value == null)
117    {
118      this.value = null;
119    }
120    else
121    {
122      this.value = new ASN1OctetString(TYPE_VALUE, value.getValue());
123    }
124  }
125
126
127
128  /**
129   * Creates a new extended request protocol op from the provided extended
130   * request object.
131   *
132   * @param  request  The extended request object to use to create this protocol
133   *                  op.
134   */
135  public ExtendedRequestProtocolOp(@NotNull final ExtendedRequest request)
136  {
137    oid   = request.getOID();
138    value = request.getValue();
139  }
140
141
142
143  /**
144   * Creates a new extended request protocol op read from the provided ASN.1
145   * stream reader.
146   *
147   * @param  reader  The ASN.1 stream reader from which to read the extended
148   *                 request protocol op.
149   *
150   * @throws  LDAPException  If a problem occurs while reading or parsing the
151   *                         extended request.
152   */
153  ExtendedRequestProtocolOp(@NotNull final ASN1StreamReader reader)
154       throws LDAPException
155  {
156    try
157    {
158      final ASN1StreamReaderSequence opSequence = reader.beginSequence();
159      oid = reader.readString();
160      Validator.ensureNotNull(oid);
161
162      if (opSequence.hasMoreElements())
163      {
164        value = new ASN1OctetString(TYPE_VALUE, reader.readBytes());
165      }
166      else
167      {
168        value = null;
169      }
170    }
171    catch (final Exception e)
172    {
173      Debug.debugException(e);
174
175      throw new LDAPException(ResultCode.DECODING_ERROR,
176           ERR_EXTENDED_REQUEST_CANNOT_DECODE.get(
177                StaticUtils.getExceptionMessage(e)),
178           e);
179    }
180  }
181
182
183
184  /**
185   * Retrieves the OID for this extended request.
186   *
187   * @return  The OID for this extended request.
188   */
189  @NotNull()
190  public String getOID()
191  {
192    return oid;
193  }
194
195
196
197  /**
198   * Retrieves the value for this extended request, if any.
199   *
200   * @return  The value for this extended request, or {@code null} if there is
201   *          no value.
202   */
203  @Nullable()
204  public ASN1OctetString getValue()
205  {
206    return value;
207  }
208
209
210
211  /**
212   * {@inheritDoc}
213   */
214  @Override()
215  public byte getProtocolOpType()
216  {
217    return LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST;
218  }
219
220
221
222  /**
223   * {@inheritDoc}
224   */
225  @Override()
226  @NotNull()
227  public ASN1Element encodeProtocolOp()
228  {
229    if (value ==  null)
230    {
231      return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST,
232           new ASN1OctetString(TYPE_OID, oid));
233    }
234    else
235    {
236      return new ASN1Sequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST,
237           new ASN1OctetString(TYPE_OID, oid),
238           value);
239    }
240  }
241
242
243
244  /**
245   * Decodes the provided ASN.1 element as an extended request protocol op.
246   *
247   * @param  element  The ASN.1 element to be decoded.
248   *
249   * @return  The decoded extended request protocol op.
250   *
251   * @throws  LDAPException  If the provided ASN.1 element cannot be decoded as
252   *                         an extended request protocol op.
253   */
254  @NotNull()
255  public static ExtendedRequestProtocolOp decodeProtocolOp(
256                     @NotNull final ASN1Element element)
257         throws LDAPException
258  {
259    try
260    {
261      final ASN1Element[] elements =
262           ASN1Sequence.decodeAsSequence(element).elements();
263      final String oid =
264           ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
265
266      final ASN1OctetString value;
267      if (elements.length == 1)
268      {
269        value = null;
270      }
271      else
272      {
273        value = ASN1OctetString.decodeAsOctetString(elements[1]);
274      }
275
276      return new ExtendedRequestProtocolOp(oid, value);
277    }
278    catch (final Exception e)
279    {
280      Debug.debugException(e);
281      throw new LDAPException(ResultCode.DECODING_ERROR,
282           ERR_EXTENDED_REQUEST_CANNOT_DECODE.get(
283                StaticUtils.getExceptionMessage(e)),
284           e);
285    }
286  }
287
288
289
290  /**
291   * {@inheritDoc}
292   */
293  @Override()
294  public void writeTo(@NotNull final ASN1Buffer buffer)
295  {
296    final ASN1BufferSequence opSequence =
297         buffer.beginSequence(LDAPMessage.PROTOCOL_OP_TYPE_EXTENDED_REQUEST);
298    buffer.addOctetString(TYPE_OID, oid);
299
300    if (value != null)
301    {
302      buffer.addOctetString(TYPE_VALUE, value.getValue());
303    }
304    opSequence.end();
305  }
306
307
308
309  /**
310   * Creates an extended request from this protocol op.
311   *
312   * @param  controls  The set of controls to include in the extended request.
313   *                   It may be empty or {@code null} if no controls should be
314   *                   included.
315   *
316   * @return  The extended request that was created.
317   */
318  @NotNull()
319  public ExtendedRequest toExtendedRequest(@Nullable final Control... controls)
320  {
321    return new ExtendedRequest(oid, value, controls);
322  }
323
324
325
326  /**
327   * Retrieves a string representation of this protocol op.
328   *
329   * @return  A string representation of this protocol op.
330   */
331  @Override()
332  @NotNull()
333  public String toString()
334  {
335    final StringBuilder buffer = new StringBuilder();
336    toString(buffer);
337    return buffer.toString();
338  }
339
340
341
342  /**
343   * {@inheritDoc}
344   */
345  @Override()
346  public void toString(@NotNull final StringBuilder buffer)
347  {
348    buffer.append("ExtendedRequestProtocolOp(oid='");
349    buffer.append(oid);
350    buffer.append("')");
351  }
352}