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