001/*
002 * Copyright 2007-2025 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-2025 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) 2007-2025 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.sdk;
037
038
039
040import java.io.Serializable;
041import java.lang.reflect.Constructor;
042import java.util.ArrayList;
043import java.util.LinkedHashMap;
044import java.util.Map;
045import java.util.concurrent.ConcurrentHashMap;
046
047import com.unboundid.asn1.ASN1Boolean;
048import com.unboundid.asn1.ASN1Buffer;
049import com.unboundid.asn1.ASN1BufferSequence;
050import com.unboundid.asn1.ASN1Constants;
051import com.unboundid.asn1.ASN1Element;
052import com.unboundid.asn1.ASN1Exception;
053import com.unboundid.asn1.ASN1OctetString;
054import com.unboundid.asn1.ASN1Sequence;
055import com.unboundid.asn1.ASN1StreamReader;
056import com.unboundid.asn1.ASN1StreamReaderSequence;
057import com.unboundid.ldap.sdk.controls.AssertionRequestControl;
058import com.unboundid.ldap.sdk.controls.AuthorizationIdentityRequestControl;
059import com.unboundid.ldap.sdk.controls.AuthorizationIdentityResponseControl;
060import com.unboundid.ldap.sdk.controls.DraftLDUPSubentriesRequestControl;
061import com.unboundid.ldap.sdk.controls.ManageDsaITRequestControl;
062import com.unboundid.ldap.sdk.controls.MatchedValuesRequestControl;
063import com.unboundid.ldap.sdk.controls.PasswordExpiredControl;
064import com.unboundid.ldap.sdk.controls.PasswordExpiringControl;
065import com.unboundid.ldap.sdk.controls.PermissiveModifyRequestControl;
066import com.unboundid.ldap.sdk.controls.PostReadRequestControl;
067import com.unboundid.ldap.sdk.controls.PostReadResponseControl;
068import com.unboundid.ldap.sdk.controls.PreReadRequestControl;
069import com.unboundid.ldap.sdk.controls.PreReadResponseControl;
070import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl;
071import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
072import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl;
073import com.unboundid.ldap.sdk.controls.ServerSideSortResponseControl;
074import com.unboundid.ldap.sdk.controls.SimplePagedResultsControl;
075import com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl;
076import com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl;
077import com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl;
078import com.unboundid.ldap.sdk.forgerockds.controls.
079            W3CTraceContextRequestControl;
080import com.unboundid.ldap.sdk.unboundidds.controls.AccessLogFieldRequestControl;
081import com.unboundid.ldap.sdk.unboundidds.controls.AccountUsableRequestControl;
082import com.unboundid.ldap.sdk.unboundidds.controls.AccountUsableResponseControl;
083import com.unboundid.ldap.sdk.unboundidds.controls.
084            AdministrativeOperationRequestControl;
085import com.unboundid.ldap.sdk.unboundidds.controls.
086            AssuredReplicationRequestControl;
087import com.unboundid.ldap.sdk.unboundidds.controls.
088            AssuredReplicationResponseControl;
089import com.unboundid.ldap.sdk.unboundidds.controls.ExcludeBranchRequestControl;
090import com.unboundid.ldap.sdk.unboundidds.controls.
091            ExtendedSchemaInfoRequestControl;
092import com.unboundid.ldap.sdk.unboundidds.controls.
093            GenerateAccessTokenRequestControl;
094import com.unboundid.ldap.sdk.unboundidds.controls.
095            GenerateAccessTokenResponseControl;
096import com.unboundid.ldap.sdk.unboundidds.controls.
097            GeneratePasswordRequestControl;
098import com.unboundid.ldap.sdk.unboundidds.controls.
099            GeneratePasswordResponseControl;
100import com.unboundid.ldap.sdk.unboundidds.controls.
101            GetAuthorizationEntryRequestControl;
102import com.unboundid.ldap.sdk.unboundidds.controls.
103            GetAuthorizationEntryResponseControl;
104import com.unboundid.ldap.sdk.unboundidds.controls.
105            GetBackendSetIDRequestControl;
106import com.unboundid.ldap.sdk.unboundidds.controls.
107            GetBackendSetIDResponseControl;
108import com.unboundid.ldap.sdk.unboundidds.controls.
109            GetEffectiveRightsRequestControl;
110import com.unboundid.ldap.sdk.unboundidds.controls.
111            GetPasswordPolicyStateIssuesRequestControl;
112import com.unboundid.ldap.sdk.unboundidds.controls.
113            GetPasswordPolicyStateIssuesResponseControl;
114import com.unboundid.ldap.sdk.unboundidds.controls.
115            GetRecentLoginHistoryRequestControl;
116import com.unboundid.ldap.sdk.unboundidds.controls.
117            GetRecentLoginHistoryResponseControl;
118import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDRequestControl;
119import com.unboundid.ldap.sdk.unboundidds.controls.GetServerIDResponseControl;
120import com.unboundid.ldap.sdk.unboundidds.controls.
121            GetUserResourceLimitsRequestControl;
122import com.unboundid.ldap.sdk.unboundidds.controls.
123            GetUserResourceLimitsResponseControl;
124import com.unboundid.ldap.sdk.unboundidds.controls.HardDeleteRequestControl;
125import com.unboundid.ldap.sdk.unboundidds.controls.
126            IgnoreNoUserModificationRequestControl;
127import com.unboundid.ldap.sdk.unboundidds.controls.
128            IntermediateClientRequestControl;
129import com.unboundid.ldap.sdk.unboundidds.controls.
130            IntermediateClientResponseControl;
131import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedRequestControl;
132import com.unboundid.ldap.sdk.unboundidds.controls.JSONFormattedResponseControl;
133import com.unboundid.ldap.sdk.unboundidds.controls.JoinRequestControl;
134import com.unboundid.ldap.sdk.unboundidds.controls.JoinResultControl;
135import com.unboundid.ldap.sdk.unboundidds.controls.
136            MatchingEntryCountRequestControl;
137import com.unboundid.ldap.sdk.unboundidds.controls.
138            MatchingEntryCountResponseControl;
139import com.unboundid.ldap.sdk.unboundidds.controls.
140            NameWithEntryUUIDRequestControl;
141import com.unboundid.ldap.sdk.unboundidds.controls.NoOpRequestControl;
142import com.unboundid.ldap.sdk.unboundidds.controls.
143            OperationPurposeRequestControl;
144import com.unboundid.ldap.sdk.unboundidds.controls.
145            OverrideSearchLimitsRequestControl;
146import com.unboundid.ldap.sdk.unboundidds.controls.PasswordPolicyRequestControl;
147import com.unboundid.ldap.sdk.unboundidds.controls.
148            PasswordPolicyResponseControl;
149import com.unboundid.ldap.sdk.unboundidds.controls.
150            PasswordUpdateBehaviorRequestControl;
151import com.unboundid.ldap.sdk.unboundidds.controls.
152            PasswordValidationDetailsRequestControl;
153import com.unboundid.ldap.sdk.unboundidds.controls.
154            PasswordValidationDetailsResponseControl;
155import com.unboundid.ldap.sdk.unboundidds.controls.
156            PermitUnindexedSearchRequestControl;
157import com.unboundid.ldap.sdk.unboundidds.controls.PurgePasswordRequestControl;
158import com.unboundid.ldap.sdk.unboundidds.controls.
159            RealAttributesOnlyRequestControl;
160import com.unboundid.ldap.sdk.unboundidds.controls.
161            RejectUnindexedSearchRequestControl;
162import com.unboundid.ldap.sdk.unboundidds.controls.
163            ReplicationRepairRequestControl;
164import com.unboundid.ldap.sdk.unboundidds.controls.RetainIdentityRequestControl;
165import com.unboundid.ldap.sdk.unboundidds.controls.RetirePasswordRequestControl;
166import com.unboundid.ldap.sdk.unboundidds.controls.
167            ReturnConflictEntriesRequestControl;
168import com.unboundid.ldap.sdk.unboundidds.controls.
169            RouteToBackendSetRequestControl;
170import com.unboundid.ldap.sdk.unboundidds.controls.RouteToServerRequestControl;
171import com.unboundid.ldap.sdk.unboundidds.controls.SoftDeleteResponseControl;
172import com.unboundid.ldap.sdk.unboundidds.controls.
173            SoftDeletedEntryAccessRequestControl;
174import com.unboundid.ldap.sdk.unboundidds.controls.SoftDeleteRequestControl;
175import com.unboundid.ldap.sdk.unboundidds.controls.
176            SuppressOperationalAttributeUpdateRequestControl;
177import com.unboundid.ldap.sdk.unboundidds.controls.
178            SuppressReferentialIntegrityUpdatesRequestControl;
179import com.unboundid.ldap.sdk.unboundidds.controls.UndeleteRequestControl;
180import com.unboundid.ldap.sdk.unboundidds.controls.UniquenessRequestControl;
181import com.unboundid.ldap.sdk.unboundidds.controls.UniquenessResponseControl;
182import com.unboundid.ldap.sdk.unboundidds.controls.
183            UnsolicitedCancelResponseControl;
184import com.unboundid.ldap.sdk.unboundidds.controls.
185            VirtualAttributesOnlyRequestControl;
186import com.unboundid.util.Base64;
187import com.unboundid.util.Debug;
188import com.unboundid.util.Extensible;
189import com.unboundid.util.NotMutable;
190import com.unboundid.util.NotNull;
191import com.unboundid.util.Nullable;
192import com.unboundid.util.StaticUtils;
193import com.unboundid.util.ThreadSafety;
194import com.unboundid.util.ThreadSafetyLevel;
195import com.unboundid.util.Validator;
196import com.unboundid.util.json.JSONBoolean;
197import com.unboundid.util.json.JSONObject;
198import com.unboundid.util.json.JSONString;
199import com.unboundid.util.json.JSONValue;
200
201import static com.unboundid.ldap.sdk.LDAPMessages.*;
202
203
204
205/**
206 * This class provides a data structure that represents an LDAP control.  A
207 * control is an element that may be attached to an LDAP request or response
208 * to provide additional information about the processing that should be (or has
209 * been) performed.  This class may be overridden to provide additional
210 * processing for specific types of controls.
211 * <BR><BR>
212 * A control includes the following elements:
213 * <UL>
214 *   <LI>An object identifier (OID), which identifies the type of control.</LI>
215 *   <LI>A criticality flag, which indicates whether the control should be
216 *       considered critical to the processing of the operation.  If a control
217 *       is marked critical but the server either does not support that control
218 *       or it is not appropriate for the associated request, then the server
219 *       will reject the request.  If a control is not marked critical and the
220 *       server either does not support it or it is not appropriate for the
221 *       associated request, then the server will simply ignore that
222 *       control and process the request as if it were not present.</LI>
223 *   <LI>An optional value, which provides additional information for the
224 *       control.  Some controls do not take values, and the value encoding for
225 *       controls which do take values varies based on the type of control.</LI>
226 * </UL>
227 * Controls may be included in a request from the client to the server, as well
228 * as responses from the server to the client (including intermediate response,
229 * search result entry, and search result references, in addition to the final
230 * response message for an operation).  When using request controls, they may be
231 * included in the request object at the time it is created, or may be added
232 * after the fact for {@link UpdatableLDAPRequest} objects.  When using
233 * response controls, each response control class includes a {@code get} method
234 * that can be used to extract the appropriate control from an appropriate
235 * result (e.g.,  {@link LDAPResult}, {@link SearchResultEntry}, or
236 * {@link SearchResultReference}).
237 */
238@Extensible()
239@NotMutable()
240@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
241public class Control
242       implements Serializable
243{
244  /**
245   * The BER type to use for the encoded set of controls in an LDAP message.
246   */
247  private static final byte CONTROLS_TYPE = (byte) 0xA0;
248
249
250
251  /**
252   * A map of the decodable control classes that have been registered with the
253   * LDAP SDK, mapped from OID to fully-qualified class name.
254   */
255  @NotNull static final ConcurrentHashMap<String,String>
256       DECODEABLE_CONTROL_CLASS_NAMES = new ConcurrentHashMap<>();
257
258
259
260  /**
261   * A map of the instantiated decodeable control classes registered with the
262   * LDAP SDK, mapped from OID to class instance.
263   */
264  @NotNull private static final ConcurrentHashMap<String,DecodeableControl>
265       DECODEABLE_CONTROL_INSTANCES = new ConcurrentHashMap<>();
266
267
268
269  /**
270   * The serial version UID for this serializable class.
271   */
272  private static final long serialVersionUID = 4440956109070220054L;
273
274
275
276  // The encoded value for this control, if there is one.
277  @Nullable private final ASN1OctetString value;
278
279  // Indicates whether this control should be considered critical.
280  private final boolean isCritical;
281
282  // The OID for this control
283  @NotNull private final String oid;
284
285
286
287  static
288  {
289    com.unboundid.ldap.sdk.controls.ControlHelper.
290         registerDefaultResponseControls();
291    com.unboundid.ldap.sdk.experimental.ControlHelper.
292         registerDefaultResponseControls();
293    com.unboundid.ldap.sdk.forgerockds.controls.ControlHelper.
294         registerDefaultResponseControls();
295    com.unboundid.ldap.sdk.unboundidds.controls.ControlHelper.
296         registerDefaultResponseControls();
297  }
298
299
300
301  /**
302   * Creates a new empty control instance that is intended to be used only for
303   * decoding controls via the {@code DecodeableControl} interface.  All
304   * {@code DecodeableControl} objects must provide a default constructor that
305   * can be used to create an instance suitable for invoking the
306   * {@code decodeControl} method.
307   */
308  protected Control()
309  {
310    oid        = null;
311    isCritical = true;
312    value      = null;
313  }
314
315
316
317  /**
318   * Creates a new control whose fields are initialized from the contents of the
319   * provided control.
320   *
321   * @param  control  The control whose information should be used to create
322   *                  this new control.
323   */
324  protected Control(@NotNull final Control control)
325  {
326    oid        = control.oid;
327    isCritical = control.isCritical;
328    value      = control.value;
329  }
330
331
332
333  /**
334   * Creates a new control with the provided OID.  It will not be critical, and
335   * it will not have a value.
336   *
337   * @param  oid  The OID for this control.  It must not be {@code null}.
338   */
339  public Control(@NotNull final String oid)
340  {
341    Validator.ensureNotNull(oid);
342
343    this.oid   = oid;
344    isCritical = false;
345    value      = null;
346  }
347
348
349
350  /**
351   * Creates a new control with the provided OID and criticality.  It will not
352   * have a value.
353   *
354   * @param  oid         The OID for this control.  It must not be {@code null}.
355   * @param  isCritical  Indicates whether this control should be considered
356   *                     critical.
357   */
358  public Control(@NotNull final String oid, final boolean isCritical)
359  {
360    Validator.ensureNotNull(oid);
361
362    this.oid        = oid;
363    this.isCritical = isCritical;
364    value           = null;
365  }
366
367
368
369  /**
370   * Creates a new control with the provided information.
371   *
372   * @param  oid         The OID for this control.  It must not be {@code null}.
373   * @param  isCritical  Indicates whether this control should be considered
374   *                     critical.
375   * @param  value       The value for this control.  It may be {@code null} if
376   *                     there is no value.
377   */
378  public Control(@NotNull final String oid, final boolean isCritical,
379                 @Nullable final ASN1OctetString value)
380  {
381    Validator.ensureNotNull(oid);
382
383    this.oid        = oid;
384    this.isCritical = isCritical;
385    this.value      = value;
386  }
387
388
389
390  /**
391   * Retrieves the OID for this control.
392   *
393   * @return  The OID for this control.
394   */
395  @NotNull()
396  public final String getOID()
397  {
398    return oid;
399  }
400
401
402
403  /**
404   * Indicates whether this control should be considered critical.
405   *
406   * @return  {@code true} if this control should be considered critical, or
407   *          {@code false} if not.
408   */
409  public final boolean isCritical()
410  {
411    return isCritical;
412  }
413
414
415
416  /**
417   * Indicates whether this control has a value.
418   *
419   * @return  {@code true} if this control has a value, or {@code false} if not.
420   */
421  public final boolean hasValue()
422  {
423    return (value != null);
424  }
425
426
427
428  /**
429   * Retrieves the encoded value for this control.
430   *
431   * @return  The encoded value for this control, or {@code null} if there is no
432   *          value.
433   */
434  @Nullable()
435  public final ASN1OctetString getValue()
436  {
437    return value;
438  }
439
440
441
442  /**
443   * Writes an ASN.1-encoded representation of this control to the provided
444   * ASN.1 stream writer.
445   *
446   * @param  writer  The ASN.1 stream writer to which the encoded representation
447   *                 should be written.
448   */
449  public final void writeTo(@NotNull final ASN1Buffer writer)
450  {
451    final ASN1BufferSequence controlSequence = writer.beginSequence();
452    writer.addOctetString(oid);
453
454    if (isCritical)
455    {
456      writer.addBoolean(true);
457    }
458
459    if (value != null)
460    {
461      writer.addOctetString(value.getValue());
462    }
463
464    controlSequence.end();
465  }
466
467
468
469  /**
470   * Encodes this control to an ASN.1 sequence suitable for use in an LDAP
471   * message.
472   *
473   * @return  The encoded representation of this control.
474   */
475  @NotNull()
476  public final ASN1Sequence encode()
477  {
478    final ArrayList<ASN1Element> elementList = new ArrayList<>(3);
479    elementList.add(new ASN1OctetString(oid));
480
481    if (isCritical)
482    {
483      elementList.add(new ASN1Boolean(isCritical));
484    }
485
486    if (value != null)
487    {
488      elementList.add(new ASN1OctetString(value.getValue()));
489    }
490
491    return new ASN1Sequence(elementList);
492  }
493
494
495
496  /**
497   * Reads an LDAP control from the provided ASN.1 stream reader.
498   *
499   * @param  reader  The ASN.1 stream reader from which to read the control.
500   *
501   * @return  The decoded control.
502   *
503   * @throws  LDAPException  If a problem occurs while attempting to read or
504   *                         parse the control.
505   */
506  @NotNull()
507  public static Control readFrom(@NotNull final ASN1StreamReader reader)
508         throws LDAPException
509  {
510    try
511    {
512      final ASN1StreamReaderSequence controlSequence = reader.beginSequence();
513      final String oid = reader.readString();
514
515      boolean isCritical = false;
516      ASN1OctetString value = null;
517      while (controlSequence.hasMoreElements())
518      {
519        final byte type = (byte) reader.peek();
520        switch (type)
521        {
522          case ASN1Constants.UNIVERSAL_BOOLEAN_TYPE:
523            isCritical = reader.readBoolean();
524            break;
525          case ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE:
526            value = new ASN1OctetString(reader.readBytes());
527            break;
528          default:
529            throw new LDAPException(ResultCode.DECODING_ERROR,
530                 ERR_CONTROL_INVALID_TYPE.get(StaticUtils.toHex(type)));
531        }
532      }
533
534      return decode(oid, isCritical, value);
535    }
536    catch (final LDAPException le)
537    {
538      Debug.debugException(le);
539      throw le;
540    }
541    catch (final Exception e)
542    {
543      Debug.debugException(e);
544      throw new LDAPException(ResultCode.DECODING_ERROR,
545           ERR_CONTROL_CANNOT_DECODE.get(StaticUtils.getExceptionMessage(e)),
546           e);
547    }
548  }
549
550
551
552  /**
553   * Decodes the provided ASN.1 sequence as an LDAP control.
554   *
555   * @param  controlSequence  The ASN.1 sequence to be decoded.
556   *
557   * @return  The decoded control.
558   *
559   * @throws  LDAPException  If a problem occurs while attempting to decode the
560   *                         provided ASN.1 sequence as an LDAP control.
561   */
562  @NotNull()
563  public static Control decode(@NotNull final ASN1Sequence controlSequence)
564         throws LDAPException
565  {
566    final ASN1Element[] elements = controlSequence.elements();
567
568    if ((elements.length < 1) || (elements.length > 3))
569    {
570      throw new LDAPException(ResultCode.DECODING_ERROR,
571                              ERR_CONTROL_DECODE_INVALID_ELEMENT_COUNT.get(
572                                   elements.length));
573    }
574
575    final String oid =
576         ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
577
578    boolean isCritical = false;
579    ASN1OctetString value = null;
580    if (elements.length == 2)
581    {
582      switch (elements[1].getType())
583      {
584        case ASN1Constants.UNIVERSAL_BOOLEAN_TYPE:
585          try
586          {
587            isCritical =
588                 ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
589          }
590          catch (final ASN1Exception ae)
591          {
592            Debug.debugException(ae);
593            throw new LDAPException(ResultCode.DECODING_ERROR,
594                 ERR_CONTROL_DECODE_CRITICALITY.get(
595                      StaticUtils.getExceptionMessage(ae)),
596                 ae);
597          }
598          break;
599
600        case ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE:
601          value = ASN1OctetString.decodeAsOctetString(elements[1]);
602          break;
603
604        default:
605          throw new LDAPException(ResultCode.DECODING_ERROR,
606               ERR_CONTROL_INVALID_TYPE.get(
607                    StaticUtils.toHex(elements[1].getType())));
608      }
609    }
610    else if (elements.length == 3)
611    {
612      try
613      {
614        isCritical = ASN1Boolean.decodeAsBoolean(elements[1]).booleanValue();
615      }
616      catch (final ASN1Exception ae)
617      {
618        Debug.debugException(ae);
619        throw new LDAPException(ResultCode.DECODING_ERROR,
620             ERR_CONTROL_DECODE_CRITICALITY.get(
621                  StaticUtils.getExceptionMessage(ae)),
622             ae);
623      }
624
625      value = ASN1OctetString.decodeAsOctetString(elements[2]);
626    }
627
628    return decode(oid, isCritical, value);
629  }
630
631
632
633  /**
634   * Attempts to create the most appropriate control instance from the provided
635   * information.  If a {@link DecodeableControl} instance has been registered
636   * for the specified OID, then this method will attempt to use that instance
637   * to construct a control.  If that fails, or if no appropriate
638   * {@code DecodeableControl} is registered, then a generic control will be
639   * returned.
640   *
641   * @param  oid         The OID for the control.  It must not be {@code null}.
642   * @param  isCritical  Indicates whether the control should be considered
643   *                     critical.
644   * @param  value       The value for the control.  It may be {@code null} if
645   *                     there is no value.
646   *
647   * @return  The decoded control.
648   *
649   * @throws  LDAPException  If a problem occurs while attempting to decode the
650   *                         provided ASN.1 sequence as an LDAP control.
651   */
652  @NotNull()
653  public static Control decode(@NotNull final String oid,
654                               final boolean isCritical,
655                               @Nullable final ASN1OctetString value)
656         throws LDAPException
657  {
658    DecodeableControl decodeableControl = DECODEABLE_CONTROL_INSTANCES.get(oid);
659    if (decodeableControl == null)
660    {
661      final String controlClassName = DECODEABLE_CONTROL_CLASS_NAMES.get(oid);
662      if (controlClassName == null)
663      {
664        return new Control(oid, isCritical, value);
665      }
666
667      try
668      {
669        final Class<?> controlClass = Class.forName(controlClassName);
670        final Constructor<?> noArgumentConstructor =
671             controlClass.getDeclaredConstructor();
672        noArgumentConstructor.setAccessible(true);
673        decodeableControl =
674             (DecodeableControl) noArgumentConstructor.newInstance();
675      }
676      catch (final Exception e)
677      {
678        Debug.debugException(e);
679        return new Control(oid, isCritical, value);
680      }
681    }
682
683    try
684    {
685      return decodeableControl.decodeControl(oid, isCritical, value);
686    }
687    catch (final Exception e)
688    {
689      Debug.debugException(e);
690      return new Control(oid, isCritical, value);
691    }
692  }
693
694
695
696  /**
697   * Encodes the provided set of controls to an ASN.1 sequence suitable for
698   * inclusion in an LDAP message.
699   *
700   * @param  controls  The set of controls to be encoded.
701   *
702   * @return  An ASN.1 sequence containing the encoded set of controls.
703   */
704  @NotNull()
705  public static ASN1Sequence encodeControls(@NotNull final Control[] controls)
706  {
707    final ASN1Sequence[] controlElements = new ASN1Sequence[controls.length];
708    for (int i=0; i < controls.length; i++)
709    {
710      controlElements[i] = controls[i].encode();
711    }
712
713    return new ASN1Sequence(CONTROLS_TYPE, controlElements);
714  }
715
716
717
718  /**
719   * Decodes the contents of the provided sequence as a set of controls.
720   *
721   * @param  controlSequence  The ASN.1 sequence containing the encoded set of
722   *                          controls.
723   *
724   * @return  The decoded set of controls.
725   *
726   * @throws  LDAPException  If a problem occurs while attempting to decode any
727   *                         of the controls.
728   */
729  @NotNull()
730  public static Control[] decodeControls(
731                               @NotNull final ASN1Sequence controlSequence)
732         throws LDAPException
733  {
734    final ASN1Element[] controlElements = controlSequence.elements();
735    final Control[] controls = new Control[controlElements.length];
736
737    for (int i=0; i < controlElements.length; i++)
738    {
739      try
740      {
741        controls[i] = decode(ASN1Sequence.decodeAsSequence(controlElements[i]));
742      }
743      catch (final ASN1Exception ae)
744      {
745        Debug.debugException(ae);
746        throw new LDAPException(ResultCode.DECODING_ERROR,
747             ERR_CONTROLS_DECODE_ELEMENT_NOT_SEQUENCE.get(
748                  StaticUtils.getExceptionMessage(ae)),
749             ae);
750      }
751    }
752
753    return controls;
754  }
755
756
757
758  /**
759   * Registers the specified class to be used in an attempt to decode controls
760   * with the specified OID.
761   *
762   * @param  oid        The response control OID for which the provided class
763   *                    will be registered.
764   * @param  className  The fully-qualified name for the Java class that
765   *                    provides the decodeable control implementation to use
766   *                    for the provided OID.
767   */
768  public static void registerDecodeableControl(@NotNull final String oid,
769                                               @NotNull final String className)
770  {
771    DECODEABLE_CONTROL_CLASS_NAMES.put(oid, className);
772    DECODEABLE_CONTROL_INSTANCES.remove(oid);
773  }
774
775
776
777  /**
778   * Registers the provided class to be used in an attempt to decode controls
779   * with the specified OID.
780   *
781   * @param  oid              The response control OID for which the provided
782   *                          class will be registered.
783   * @param  controlInstance  The control instance that should be used to decode
784   *                          controls with the provided OID.
785   */
786  public static void registerDecodeableControl(@NotNull final String oid,
787                          @NotNull final DecodeableControl controlInstance)
788  {
789    DECODEABLE_CONTROL_CLASS_NAMES.put(oid,
790         controlInstance.getClass().getName());
791    DECODEABLE_CONTROL_INSTANCES.put(oid, controlInstance);
792  }
793
794
795
796  /**
797   * Deregisters the decodeable control class associated with the provided OID.
798   *
799   * @param  oid  The response control OID for which to deregister the
800   *              decodeable control class.
801   */
802  public static void deregisterDecodeableControl(@NotNull final String oid)
803  {
804    DECODEABLE_CONTROL_CLASS_NAMES.remove(oid);
805    DECODEABLE_CONTROL_INSTANCES.remove(oid);
806  }
807
808
809
810  /**
811   * Retrieves a hash code for this control.
812   *
813   * @return  A hash code for this control.
814   */
815  @Override()
816  public final int hashCode()
817  {
818    int hashCode = oid.hashCode();
819
820    if (isCritical)
821    {
822      hashCode++;
823    }
824
825    if (value != null)
826    {
827      hashCode += value.hashCode();
828    }
829
830    return hashCode;
831  }
832
833
834
835  /**
836   * Indicates whether the provided object may be considered equal to this
837   * control.
838   *
839   * @param  o  The object for which to make the determination.
840   *
841   * @return  {@code true} if the provided object may be considered equal to
842   *          this control, or {@code false} if not.
843   */
844  @Override()
845  public final boolean equals(@Nullable final Object o)
846  {
847    if (o == null)
848    {
849      return false;
850    }
851
852    if (o == this)
853    {
854      return true;
855    }
856
857    if (! (o instanceof Control))
858    {
859      return false;
860    }
861
862    final Control c = (Control) o;
863    if (! oid.equals(c.oid))
864    {
865      return false;
866    }
867
868    if (isCritical != c.isCritical)
869    {
870      return false;
871    }
872
873    if (value == null)
874    {
875      if (c.value != null)
876      {
877        return false;
878      }
879    }
880    else
881    {
882      if (c.value == null)
883      {
884        return false;
885      }
886
887      if (! value.equals(c.value))
888      {
889        return false;
890      }
891    }
892
893
894    return true;
895  }
896
897
898
899  /**
900   * Retrieves the user-friendly name for this control, if available.  If no
901   * user-friendly name has been defined, then the OID will be returned.
902   *
903   * @return  The user-friendly name for this control, or the OID if no
904   *          user-friendly name is available.
905   */
906  @NotNull()
907  public String getControlName()
908  {
909    // By default, we will return the OID.  Subclasses should override this to
910    // provide the user-friendly name.
911    return oid;
912  }
913
914
915
916  /**
917   * Retrieves a representation of this control as a JSON object.  The JSON
918   * object uses the following fields:
919   * <UL>
920   *   <LI>
921   *     {@code oid} -- A mandatory string field whose value is the object
922   *     identifier for this control.
923   *   </LI>
924   *   <LI>
925   *     {@code control-name} -- An optional string field whose value is a
926   *     human-readable name for this control.  This field is only intended for
927   *     descriptive purposes, and when decoding a control, the {@code oid}
928   *     field should be used to identify the type of control.
929   *   </LI>
930   *   <LI>
931   *     {@code criticality} -- A mandatory Boolean field used to indicate
932   *     whether this control is considered critical.
933   *   </LI>
934   *   <LI>
935   *     {@code value-base64} -- An optional string field whose value is a
936   *     base64-encoded representation of the raw value for this control.  At
937   *     most one of the {@code value-base64} and {@code value-json} fields may
938   *     be present, and both fields will be absent for controls that do not
939   *     have a value.
940   *   </LI>
941   *   <LI>
942   *     {@code value-json} -- An optional JSON object field whose value is a
943   *     user-friendly, control-specific representation of the value for this
944   *     control.  This representation of the value is only available for
945   *     certain types of controls, and subclasses will override this method to
946   *     provide an appropriate representation of that value, and their Javadoc
947   *     documentation will describe the fields that may be present in the
948   *     value.  At most one of the  {@code value-base64} and {@code value-json}
949   *     fields may be present, and both fields will be absent for controls that
950   *     do not have a value.
951   *   </LI>
952   * </UL>
953   *
954   * @return  A JSON object that contains a representation of this control.
955   */
956  @NotNull()
957  public JSONObject toJSONControl()
958  {
959    final Map<String,JSONValue> fields = new LinkedHashMap<>(
960         StaticUtils.computeMapCapacity(4));
961
962    fields.put(JSONControlDecodeHelper.JSON_FIELD_OID, new JSONString(oid));
963
964    final String name = getControlName();
965    if ((name != null) && (! name.equals(oid)))
966    {
967      fields.put(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
968           new JSONString(name));
969    }
970
971    fields.put(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
972         new JSONBoolean(isCritical));
973
974    if (value != null)
975    {
976      fields.put(JSONControlDecodeHelper.JSON_FIELD_VALUE_BASE64,
977           new JSONString(Base64.encode(value.getValue())));
978    }
979
980    return new JSONObject(fields);
981  }
982
983
984
985  /**
986   * Attempts to decode the provided object as a JSON representation of a
987   * control.  If the OID extracted from the provided JSON object matches the
988   * OID for a control with a known-supported encoding, then control-specific
989   * decoding will be used to allow for a more user-friendly version of the
990   * object (for example, with a value formatted as a JSON object rather than
991   * raw base64-encoded data).  If no specific support is available for the
992   * specified control, then a more generic decoding will be used, and only
993   * base64-encoded values will be supported.
994   *
995   * @param  controlObject     The JSON object to be decoded.  It must not be
996   *                           {@code null}.
997   * @param  strict            Indicates whether to use strict mode when
998   *                           decoding the provided JSON object.  If this is
999   *                           {@code true}, then this method will throw an
1000   *                           exception if the provided JSON object contains
1001   *                           any unrecognized fields, and potentially if any
1002   *                           other constraints are violated.  If this is
1003   *                           {@code false}, then unrecognized fields will be
1004   *                           ignored, and potentially other lenient parsing
1005   *                           will be used.
1006   * @param  isRequestControl  Indicates whether the provided JSON object
1007   *                           represents a request control (if {@code true})
1008   *                           rather than a response control
1009   *                           (if {@code false}).  This will be used in cases
1010   *                           where both a request and response control of the
1011   *                           same type share the same OID.
1012   *
1013   * @return  The control that was decoded from the provided JSON object.
1014   *
1015   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
1016   *                         valid control.
1017   */
1018  @NotNull()
1019  public static Control decodeJSONControl(
1020              @NotNull final JSONObject controlObject,
1021              final boolean strict,
1022              final boolean isRequestControl)
1023         throws LDAPException
1024  {
1025    final String oid = controlObject.getFieldAsString(
1026         JSONControlDecodeHelper.JSON_FIELD_OID);
1027    if (oid == null)
1028    {
1029      throw new LDAPException(ResultCode.DECODING_ERROR,
1030           ERR_CONTROL_JSON_OBJECT_MISSING_OID.get(
1031                controlObject.toSingleLineString(),
1032                JSONControlDecodeHelper.JSON_FIELD_OID));
1033    }
1034
1035    switch (oid)
1036    {
1037      case AccessLogFieldRequestControl.ACCESS_LOG_FIELD_REQUEST_OID:
1038        return AccessLogFieldRequestControl.decodeJSONControl(
1039             controlObject, strict);
1040
1041      // NOTE:  The account usable request and response controls use the same
1042      // OID.
1043      case AccountUsableRequestControl.ACCOUNT_USABLE_REQUEST_OID:
1044        if (isRequestControl)
1045        {
1046          return AccountUsableRequestControl.decodeJSONControl(
1047               controlObject, strict);
1048        }
1049        else
1050        {
1051          return AccountUsableResponseControl.decodeJSONControl(
1052               controlObject, strict);
1053        }
1054
1055      case AdministrativeOperationRequestControl.
1056           ADMINISTRATIVE_OPERATION_REQUEST_OID:
1057        return AdministrativeOperationRequestControl.decodeJSONControl(
1058             controlObject, strict);
1059
1060      case AssertionRequestControl.ASSERTION_REQUEST_OID:
1061        return AssertionRequestControl.decodeJSONControl(controlObject, strict);
1062
1063      case AssuredReplicationRequestControl.ASSURED_REPLICATION_REQUEST_OID:
1064        return AssuredReplicationRequestControl.decodeJSONControl(
1065             controlObject, strict);
1066
1067      case AssuredReplicationResponseControl.ASSURED_REPLICATION_RESPONSE_OID:
1068        return AssuredReplicationResponseControl.decodeJSONControl(
1069             controlObject, strict);
1070
1071      case AuthorizationIdentityRequestControl.
1072           AUTHORIZATION_IDENTITY_REQUEST_OID:
1073        return AuthorizationIdentityRequestControl.decodeJSONControl(
1074             controlObject, strict);
1075
1076      case AuthorizationIdentityResponseControl.
1077           AUTHORIZATION_IDENTITY_RESPONSE_OID:
1078        return AuthorizationIdentityResponseControl.decodeJSONControl(
1079             controlObject, strict);
1080
1081      case DraftLDUPSubentriesRequestControl.SUBENTRIES_REQUEST_OID:
1082        return DraftLDUPSubentriesRequestControl.decodeJSONControl(
1083             controlObject, strict);
1084
1085      case ExcludeBranchRequestControl.EXCLUDE_BRANCH_REQUEST_OID:
1086        return ExcludeBranchRequestControl.decodeJSONControl(
1087             controlObject, strict);
1088
1089      case ExtendedSchemaInfoRequestControl.EXTENDED_SCHEMA_INFO_REQUEST_OID:
1090        return ExtendedSchemaInfoRequestControl.decodeJSONControl(
1091             controlObject, strict);
1092
1093      case GenerateAccessTokenRequestControl.GENERATE_ACCESS_TOKEN_REQUEST_OID:
1094        return GenerateAccessTokenRequestControl.decodeJSONControl(
1095             controlObject, strict);
1096
1097      case GenerateAccessTokenResponseControl.
1098           GENERATE_ACCESS_TOKEN_RESPONSE_OID:
1099        return GenerateAccessTokenResponseControl.decodeJSONControl(
1100             controlObject, strict);
1101
1102      case GeneratePasswordRequestControl.GENERATE_PASSWORD_REQUEST_OID:
1103        return GeneratePasswordRequestControl.decodeJSONControl(
1104             controlObject, strict);
1105
1106      case GeneratePasswordResponseControl.GENERATE_PASSWORD_RESPONSE_OID:
1107        return GeneratePasswordResponseControl.decodeJSONControl(
1108             controlObject, strict);
1109
1110      // NOTE:  The get authorization entry request and response controls use
1111      // the same OID.
1112      case GetAuthorizationEntryRequestControl.
1113           GET_AUTHORIZATION_ENTRY_REQUEST_OID:
1114        if (isRequestControl)
1115        {
1116          return GetAuthorizationEntryRequestControl.decodeJSONControl(
1117               controlObject, strict);
1118        }
1119        else
1120        {
1121          return GetAuthorizationEntryResponseControl.decodeJSONControl(
1122               controlObject, strict);
1123        }
1124
1125      case GetBackendSetIDRequestControl.GET_BACKEND_SET_ID_REQUEST_OID:
1126        return GetBackendSetIDRequestControl.decodeJSONControl(
1127             controlObject, strict);
1128
1129      case GetBackendSetIDResponseControl.GET_BACKEND_SET_ID_RESPONSE_OID:
1130        return GetBackendSetIDResponseControl.decodeJSONControl(
1131             controlObject, strict);
1132
1133      case GetEffectiveRightsRequestControl.GET_EFFECTIVE_RIGHTS_REQUEST_OID:
1134        return GetEffectiveRightsRequestControl.decodeJSONControl(
1135             controlObject, strict);
1136
1137      case GetPasswordPolicyStateIssuesRequestControl.
1138           GET_PASSWORD_POLICY_STATE_ISSUES_REQUEST_OID:
1139        return GetPasswordPolicyStateIssuesRequestControl.decodeJSONControl(
1140             controlObject, strict);
1141
1142      case GetPasswordPolicyStateIssuesResponseControl.
1143           GET_PASSWORD_POLICY_STATE_ISSUES_RESPONSE_OID:
1144        return GetPasswordPolicyStateIssuesResponseControl.decodeJSONControl(
1145             controlObject, strict);
1146
1147      case GetRecentLoginHistoryRequestControl.
1148           GET_RECENT_LOGIN_HISTORY_REQUEST_OID:
1149        return GetRecentLoginHistoryRequestControl.decodeJSONControl(
1150             controlObject, strict);
1151
1152      case GetRecentLoginHistoryResponseControl.
1153           GET_RECENT_LOGIN_HISTORY_RESPONSE_OID:
1154        return GetRecentLoginHistoryResponseControl.decodeJSONControl(
1155             controlObject, strict);
1156
1157      case GetServerIDRequestControl.GET_SERVER_ID_REQUEST_OID:
1158        return GetServerIDRequestControl.decodeJSONControl(
1159             controlObject, strict);
1160
1161      case GetServerIDResponseControl.GET_SERVER_ID_RESPONSE_OID:
1162        return GetServerIDResponseControl.decodeJSONControl(
1163             controlObject, strict);
1164
1165      case GetUserResourceLimitsRequestControl.
1166           GET_USER_RESOURCE_LIMITS_REQUEST_OID:
1167        return GetUserResourceLimitsRequestControl.decodeJSONControl(
1168             controlObject, strict);
1169
1170      case GetUserResourceLimitsResponseControl.
1171           GET_USER_RESOURCE_LIMITS_RESPONSE_OID:
1172        return GetUserResourceLimitsResponseControl.decodeJSONControl(
1173             controlObject, strict);
1174
1175      case HardDeleteRequestControl.HARD_DELETE_REQUEST_OID:
1176        return HardDeleteRequestControl.decodeJSONControl(
1177             controlObject, strict);
1178
1179      case IgnoreNoUserModificationRequestControl.
1180           IGNORE_NO_USER_MODIFICATION_REQUEST_OID:
1181        return IgnoreNoUserModificationRequestControl.decodeJSONControl(
1182             controlObject, strict);
1183
1184      // NOTE:  The intermediate client request and response controls use the
1185      // same OID.
1186      case IntermediateClientRequestControl.INTERMEDIATE_CLIENT_REQUEST_OID:
1187        if (isRequestControl)
1188        {
1189          return IntermediateClientRequestControl.decodeJSONControl(
1190               controlObject, strict);
1191        }
1192        else
1193        {
1194          return IntermediateClientResponseControl.decodeJSONControl(
1195               controlObject, strict);
1196        }
1197
1198      // NOTE:  The join request and result controls use the same OID.
1199      case JoinRequestControl.JOIN_REQUEST_OID:
1200        if (isRequestControl)
1201        {
1202          return JoinRequestControl.decodeJSONControl(controlObject, strict);
1203        }
1204        else
1205        {
1206          return JoinResultControl.decodeJSONControl(controlObject, strict);
1207        }
1208
1209      case JSONFormattedRequestControl.JSON_FORMATTED_REQUEST_OID:
1210        return JSONFormattedRequestControl.decodeJSONControl(
1211             controlObject, strict);
1212
1213      case JSONFormattedResponseControl.JSON_FORMATTED_RESPONSE_OID:
1214        return JSONFormattedResponseControl.decodeJSONControl(
1215             controlObject, strict);
1216
1217      case ManageDsaITRequestControl.MANAGE_DSA_IT_REQUEST_OID:
1218        return ManageDsaITRequestControl.decodeJSONControl(
1219             controlObject, strict);
1220
1221      case MatchedValuesRequestControl.MATCHED_VALUES_REQUEST_OID:
1222        return MatchedValuesRequestControl.decodeJSONControl(
1223             controlObject, strict);
1224
1225      case MatchingEntryCountRequestControl.MATCHING_ENTRY_COUNT_REQUEST_OID:
1226        return MatchingEntryCountRequestControl.decodeJSONControl(
1227             controlObject, strict);
1228
1229      case MatchingEntryCountResponseControl.MATCHING_ENTRY_COUNT_RESPONSE_OID:
1230        return MatchingEntryCountResponseControl.decodeJSONControl(
1231             controlObject, strict);
1232
1233      case NameWithEntryUUIDRequestControl.NAME_WITH_ENTRY_UUID_REQUEST_OID:
1234        return NameWithEntryUUIDRequestControl.decodeJSONControl(
1235             controlObject, strict);
1236
1237      case NoOpRequestControl.NO_OP_REQUEST_OID:
1238        return NoOpRequestControl.decodeJSONControl(controlObject, strict);
1239
1240      case OperationPurposeRequestControl.OPERATION_PURPOSE_REQUEST_OID:
1241        return OperationPurposeRequestControl.decodeJSONControl(
1242             controlObject, strict);
1243
1244      case OverrideSearchLimitsRequestControl.
1245           OVERRIDE_SEARCH_LIMITS_REQUEST_OID:
1246        return OverrideSearchLimitsRequestControl.decodeJSONControl(
1247             controlObject, strict);
1248
1249      case PasswordExpiredControl.PASSWORD_EXPIRED_OID:
1250        return PasswordExpiredControl.decodeJSONControl(controlObject, strict);
1251
1252      case PasswordExpiringControl.PASSWORD_EXPIRING_OID:
1253        return PasswordExpiringControl.decodeJSONControl(controlObject, strict);
1254
1255      // NOTE:  The password policy request and result controls use the same
1256      // OID.
1257      case PasswordPolicyRequestControl.PASSWORD_POLICY_REQUEST_OID:
1258        if (isRequestControl)
1259        {
1260          return PasswordPolicyRequestControl.decodeJSONControl(
1261               controlObject, strict);
1262        }
1263        else
1264        {
1265          return PasswordPolicyResponseControl.decodeJSONControl(
1266               controlObject, strict);
1267        }
1268
1269      case PasswordUpdateBehaviorRequestControl.
1270           PASSWORD_UPDATE_BEHAVIOR_REQUEST_OID:
1271        return PasswordUpdateBehaviorRequestControl.decodeJSONControl(
1272             controlObject, strict);
1273
1274      case PasswordValidationDetailsRequestControl.
1275           PASSWORD_VALIDATION_DETAILS_REQUEST_OID:
1276        return PasswordValidationDetailsRequestControl.decodeJSONControl(
1277             controlObject, strict);
1278
1279      case PasswordValidationDetailsResponseControl.
1280           PASSWORD_VALIDATION_DETAILS_RESPONSE_OID:
1281        return PasswordValidationDetailsResponseControl.decodeJSONControl(
1282             controlObject, strict);
1283
1284      case PermissiveModifyRequestControl.PERMISSIVE_MODIFY_REQUEST_OID:
1285        return PermissiveModifyRequestControl.decodeJSONControl(
1286             controlObject, strict);
1287
1288      case PermitUnindexedSearchRequestControl.
1289           PERMIT_UNINDEXED_SEARCH_REQUEST_OID:
1290        return PermitUnindexedSearchRequestControl.decodeJSONControl(
1291             controlObject, strict);
1292
1293      // NOTE:  The post-read request and result controls use the same OID.
1294      case PostReadRequestControl.POST_READ_REQUEST_OID:
1295        if (isRequestControl)
1296        {
1297          return PostReadRequestControl.decodeJSONControl(
1298               controlObject, strict);
1299        }
1300        else
1301        {
1302          return PostReadResponseControl.decodeJSONControl(
1303               controlObject, strict);
1304        }
1305
1306      // NOTE:  The pre-read request and result controls use the same OID.
1307      case PreReadRequestControl.PRE_READ_REQUEST_OID:
1308        if (isRequestControl)
1309        {
1310          return PreReadRequestControl.decodeJSONControl(
1311               controlObject, strict);
1312        }
1313        else
1314        {
1315          return PreReadResponseControl.decodeJSONControl(
1316               controlObject, strict);
1317        }
1318
1319      case ProxiedAuthorizationV1RequestControl.
1320           PROXIED_AUTHORIZATION_V1_REQUEST_OID:
1321        return ProxiedAuthorizationV1RequestControl.decodeJSONControl(
1322             controlObject, strict);
1323
1324      case ProxiedAuthorizationV2RequestControl.
1325           PROXIED_AUTHORIZATION_V2_REQUEST_OID:
1326        return ProxiedAuthorizationV2RequestControl.decodeJSONControl(
1327             controlObject, strict);
1328
1329      case PurgePasswordRequestControl.PURGE_PASSWORD_REQUEST_OID:
1330        return PurgePasswordRequestControl.decodeJSONControl(
1331             controlObject, strict);
1332
1333      case RealAttributesOnlyRequestControl.REAL_ATTRIBUTES_ONLY_REQUEST_OID:
1334        return RealAttributesOnlyRequestControl.decodeJSONControl(
1335             controlObject, strict);
1336
1337      case RejectUnindexedSearchRequestControl.
1338           REJECT_UNINDEXED_SEARCH_REQUEST_OID:
1339        return RejectUnindexedSearchRequestControl.decodeJSONControl(
1340             controlObject, strict);
1341
1342      case ReplicationRepairRequestControl.REPLICATION_REPAIR_REQUEST_OID:
1343        return ReplicationRepairRequestControl.decodeJSONControl(
1344             controlObject, strict);
1345
1346      case RetainIdentityRequestControl.RETAIN_IDENTITY_REQUEST_OID:
1347        return RetainIdentityRequestControl.decodeJSONControl(
1348             controlObject, strict);
1349
1350      case RetirePasswordRequestControl.RETIRE_PASSWORD_REQUEST_OID:
1351        return RetirePasswordRequestControl.decodeJSONControl(
1352             controlObject, strict);
1353
1354      case ReturnConflictEntriesRequestControl.
1355           RETURN_CONFLICT_ENTRIES_REQUEST_OID:
1356        return ReturnConflictEntriesRequestControl.decodeJSONControl(
1357             controlObject, strict);
1358
1359      case RouteToBackendSetRequestControl.ROUTE_TO_BACKEND_SET_REQUEST_OID:
1360        return RouteToBackendSetRequestControl.decodeJSONControl(
1361             controlObject, strict);
1362
1363      case RouteToServerRequestControl.ROUTE_TO_SERVER_REQUEST_OID:
1364        return RouteToServerRequestControl.decodeJSONControl(
1365             controlObject, strict);
1366
1367      case ServerSideSortRequestControl.SERVER_SIDE_SORT_REQUEST_OID:
1368        return ServerSideSortRequestControl.decodeJSONControl(
1369             controlObject, strict);
1370
1371      case ServerSideSortResponseControl.SERVER_SIDE_SORT_RESPONSE_OID:
1372        return ServerSideSortResponseControl.decodeJSONControl(
1373             controlObject, strict);
1374
1375      case SimplePagedResultsControl.PAGED_RESULTS_OID:
1376        return SimplePagedResultsControl.decodeJSONControl(
1377             controlObject, strict);
1378
1379      case SoftDeletedEntryAccessRequestControl.
1380           SOFT_DELETED_ENTRY_ACCESS_REQUEST_OID:
1381        return SoftDeletedEntryAccessRequestControl.decodeJSONControl(
1382             controlObject, strict);
1383
1384      case SoftDeleteRequestControl.SOFT_DELETE_REQUEST_OID:
1385        return SoftDeleteRequestControl.decodeJSONControl(
1386             controlObject, strict);
1387
1388      case SoftDeleteResponseControl.SOFT_DELETE_RESPONSE_OID:
1389        return SoftDeleteResponseControl.decodeJSONControl(
1390             controlObject, strict);
1391
1392      case SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID:
1393        return SubtreeDeleteRequestControl.decodeJSONControl(
1394             controlObject, strict);
1395
1396      case SuppressOperationalAttributeUpdateRequestControl.
1397           SUPPRESS_OP_ATTR_UPDATE_REQUEST_OID:
1398        return SuppressOperationalAttributeUpdateRequestControl.
1399             decodeJSONControl(controlObject, strict);
1400
1401      case SuppressReferentialIntegrityUpdatesRequestControl.
1402           SUPPRESS_REFINT_REQUEST_OID:
1403        return SuppressReferentialIntegrityUpdatesRequestControl.
1404             decodeJSONControl(controlObject, strict);
1405
1406      case UndeleteRequestControl.UNDELETE_REQUEST_OID:
1407        return UndeleteRequestControl.decodeJSONControl(controlObject, strict);
1408
1409      case UniquenessRequestControl.UNIQUENESS_REQUEST_OID:
1410        return UniquenessRequestControl.decodeJSONControl(
1411             controlObject, strict);
1412
1413      case UniquenessResponseControl.UNIQUENESS_RESPONSE_OID:
1414        return UniquenessResponseControl.decodeJSONControl(
1415             controlObject, strict);
1416
1417      case UnsolicitedCancelResponseControl.UNSOLICITED_CANCEL_RESPONSE_OID:
1418        return UnsolicitedCancelResponseControl.decodeJSONControl(
1419             controlObject, strict);
1420
1421      case VirtualAttributesOnlyRequestControl.
1422           VIRTUAL_ATTRIBUTES_ONLY_REQUEST_OID:
1423        return VirtualAttributesOnlyRequestControl.decodeJSONControl(
1424             controlObject, strict);
1425
1426      case VirtualListViewRequestControl.VIRTUAL_LIST_VIEW_REQUEST_OID:
1427        return VirtualListViewRequestControl.decodeJSONControl(
1428             controlObject, strict);
1429
1430      case VirtualListViewResponseControl.VIRTUAL_LIST_VIEW_RESPONSE_OID:
1431        return VirtualListViewResponseControl.decodeJSONControl(
1432             controlObject, strict);
1433
1434      case W3CTraceContextRequestControl.W3C_TRACE_CONTEXT_REQUEST_OID:
1435        return W3CTraceContextRequestControl.decodeJSONControl(
1436             controlObject, strict);
1437
1438      default:
1439        // The OID doesn't match that of a control for which we provide specific
1440        // JSON support.  Treat it as a generic control.  Note that we can't
1441        // support the JSON representation of the control value.
1442        final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
1443             controlObject, strict, true, false);
1444        if (jsonControl.getValueObject() != null)
1445        {
1446          throw new LDAPException(ResultCode.DECODING_ERROR,
1447               ERR_CONTROL_JSON_UNABLE_TO_SUPPORT_VALUE_JSON.get(
1448                    controlObject.toSingleLineString(),
1449                    JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON, oid,
1450                    JSONControlDecodeHelper.JSON_FIELD_VALUE_BASE64));
1451        }
1452        else
1453        {
1454          return new Control(jsonControl.getOID(), jsonControl.getCriticality(),
1455               jsonControl.getRawValue());
1456        }
1457    }
1458  }
1459
1460
1461
1462  /**
1463   * Retrieves a string representation of this LDAP control.
1464   *
1465   * @return  A string representation of this LDAP control.
1466   */
1467  @Override()
1468  @NotNull()
1469  public String toString()
1470  {
1471    final StringBuilder buffer = new StringBuilder();
1472    toString(buffer);
1473    return buffer.toString();
1474  }
1475
1476
1477
1478  /**
1479   * Appends a string representation of this LDAP control to the provided
1480   * buffer.
1481   *
1482   * @param  buffer  The buffer to which to append the string representation of
1483   *                 this buffer.
1484   */
1485  public void toString(@NotNull final StringBuilder buffer)
1486  {
1487    buffer.append("Control(oid=");
1488    buffer.append(oid);
1489    buffer.append(", isCritical=");
1490    buffer.append(isCritical);
1491    buffer.append(", value=");
1492
1493    if (value == null)
1494    {
1495      buffer.append("{null}");
1496    }
1497    else
1498    {
1499      buffer.append("{byte[");
1500      buffer.append(value.getValue().length);
1501      buffer.append("]}");
1502    }
1503
1504    buffer.append(')');
1505  }
1506}