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