001/*
002 * Copyright 2012-2023 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2012-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) 2012-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.unboundidds.controls;
037
038
039
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.Iterator;
043import java.util.LinkedHashMap;
044import java.util.List;
045import java.util.Map;
046
047import com.unboundid.asn1.ASN1Element;
048import com.unboundid.asn1.ASN1Long;
049import com.unboundid.asn1.ASN1OctetString;
050import com.unboundid.asn1.ASN1Sequence;
051import com.unboundid.asn1.ASN1Set;
052import com.unboundid.ldap.sdk.Attribute;
053import com.unboundid.ldap.sdk.Control;
054import com.unboundid.ldap.sdk.BindResult;
055import com.unboundid.ldap.sdk.DecodeableControl;
056import com.unboundid.ldap.sdk.JSONControlDecodeHelper;
057import com.unboundid.ldap.sdk.LDAPException;
058import com.unboundid.ldap.sdk.ResultCode;
059import com.unboundid.util.Debug;
060import com.unboundid.util.NotMutable;
061import com.unboundid.util.NotNull;
062import com.unboundid.util.Nullable;
063import com.unboundid.util.StaticUtils;
064import com.unboundid.util.ThreadSafety;
065import com.unboundid.util.ThreadSafetyLevel;
066import com.unboundid.util.json.JSONArray;
067import com.unboundid.util.json.JSONField;
068import com.unboundid.util.json.JSONNumber;
069import com.unboundid.util.json.JSONObject;
070import com.unboundid.util.json.JSONString;
071import com.unboundid.util.json.JSONValue;
072
073import static com.unboundid.ldap.sdk.unboundidds.controls.ControlMessages.*;
074
075
076
077/**
078 * This class provides a response control that may be included in the response
079 * to a successful bind operation in order to provide information about custom
080 * resource limits for the user, including size limit, time limit, idle time
081 * limit, lookthrough limit, equivalent authorization user DN, and client
082 * connection policy name.
083 * <BR>
084 * <BLOCKQUOTE>
085 *   <B>NOTE:</B>  This class, and other classes within the
086 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
087 *   supported for use against Ping Identity, UnboundID, and
088 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
089 *   for proprietary functionality or for external specifications that are not
090 *   considered stable or mature enough to be guaranteed to work in an
091 *   interoperable way with other types of LDAP servers.
092 * </BLOCKQUOTE>
093 * <BR>
094 * The criticality for this control should be {@code false}.  It must have a
095 * value with the following encoding:
096 * <PRE>
097 *   USER_RESOURCE_LIMITS_VALUE ::= SEQUENCE {
098 *     sizeLimit                      [0] INTEGER OPTIONAL,
099 *     timeLimitSeconds               [1] INTEGER OPTIONAL,
100 *     idleTimeLimitSeconds           [2] INTEGER OPTIONAL,
101 *     lookthroughLimit               [3] INTEGER OPTIONAL,
102 *     equivalentAuthzUserDN          [4] LDAPDN OPTIONAL,
103 *     clientConnectionPolicyName     [5] OCTET STRING OPTIONAL,
104 *     groupDNs                       [6] SET OF OCTET STRING OPTIONAL,
105 *     privilegeNames                 [7] SET OF OCTET STRING OPTIONAL,
106 *     otherAttributes                [8] PartialAttributeList OPTIONAL,
107 *     ... }
108 * </PRE>
109 *
110 * @see GetUserResourceLimitsRequestControl
111 */
112@NotMutable()
113@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
114public final class GetUserResourceLimitsResponseControl
115       extends Control
116       implements DecodeableControl
117{
118  /**
119   * The OID (1.3.6.1.4.1.30221.2.5.26) for the get user resource limits
120   * response control.
121   */
122  @NotNull public static final String GET_USER_RESOURCE_LIMITS_RESPONSE_OID =
123       "1.3.6.1.4.1.30221.2.5.26";
124
125
126
127  /**
128   * The BER type for the value element used to specify the size limit.
129   */
130  private static final byte TYPE_SIZE_LIMIT = (byte) 0x80;
131
132
133
134  /**
135   * The BER type for the value element used to specify the time limit.
136   */
137  private static final byte TYPE_TIME_LIMIT = (byte) 0x81;
138
139
140
141  /**
142   * The BER type for the value element used to specify the idle time limit.
143   */
144  private static final byte TYPE_IDLE_TIME_LIMIT = (byte) 0x82;
145
146
147
148  /**
149   * The BER type for the value element used to specify the lookthrough limit.
150   */
151  private static final byte TYPE_LOOKTHROUGH_LIMIT = (byte) 0x83;
152
153
154
155  /**
156   * The BER type for the value element used to specify the equivalent
157   * authorization user DN.
158   */
159  private static final byte TYPE_EQUIVALENT_AUTHZ_USER_DN = (byte) 0x84;
160
161
162
163  /**
164   * The BER type for the value element used to specify the client connection
165   * policy name.
166   */
167  private static final byte TYPE_CLIENT_CONNECTION_POLICY_NAME = (byte) 0x85;
168
169
170
171  /**
172   * The BER type for the value element used to specify the DNs of groups in
173   * which the user is a member.
174   */
175  private static final byte TYPE_GROUP_DNS = (byte) 0xA6;
176
177
178
179  /**
180   * The BER type for the value element used to specify the set of user
181   * privilege names.
182   */
183  private static final byte TYPE_PRIVILEGE_NAMES = (byte) 0xA7;
184
185
186
187  /**
188   * The BER type for the value element used to specify additional attributes
189   * that may be included in the future.
190   */
191  private static final byte TYPE_OTHER_ATTRIBUTES = (byte) 0xA8;
192
193
194
195  /**
196   * The name of the field used to hold an attribute name in the JSON
197   * representation of this control.
198   */
199  @NotNull private static final String JSON_FIELD_ATTRIBUTE_NAME = "name";
200
201
202
203  /**
204   * The name of the field used to hold the set of attribute values in the JSON
205   * representation of this control.
206   */
207  @NotNull private static final String JSON_FIELD_ATTRIBUTE_VALUES = "values";
208
209
210
211  /**
212   * The name of the field used to hold the client connection policy name in the
213   * JSON representation of this control.
214   */
215  @NotNull private static final String
216       JSON_FIELD_CLIENT_CONNECTION_POLICY_NAME =
217            "client-connection-policy-name";
218
219
220
221  /**
222   * The name of the field used to hold the equivalent authorization user DN in
223   * the JSON representation of this control.
224   */
225  @NotNull private static final String JSON_FIELD_EQUIVALENT_AUTHZ_USER_DN =
226       "equivalent-authorization-user-dn";
227
228
229
230  /**
231   * The name of the field used to hold the group DNs in the JSON representation
232   * of this control.
233   */
234  @NotNull private static final String JSON_FIELD_GROUP_DNS = "group-dns";
235
236
237
238  /**
239   * The name of the field used to hold the idle time limit in the JSON
240   * representation of this control.
241   */
242  @NotNull private static final String JSON_FIELD_IDLE_TIME_LIMIT_SECONDS =
243       "idle-time-limit-seconds";
244
245
246
247  /**
248   * The name of the field used to hold the search lookthrough limit in the JSON
249   * representation of this control.
250   */
251  @NotNull private static final String JSON_FIELD_LOOKTHROUGH_LIMIT =
252       "lookthrough-limit";
253
254
255
256  /**
257   * The name of the field used to hold other attributes in the JSON
258   * representation of this control.
259   */
260  @NotNull private static final String JSON_FIELD_OTHER_ATTRIBUTES =
261       "other-attributes";
262
263
264
265  /**
266   * The name of the field used to hold the privilege names in the JSON
267   * representation of this control.
268   */
269  @NotNull private static final String JSON_FIELD_PRIVILEGE_NAMES =
270       "privilege-names";
271
272
273
274  /**
275   * The name of the field used to hold the search size limit in the JSON
276   * representation of this control.
277   */
278  @NotNull private static final String JSON_FIELD_SIZE_LIMIT = "size-limit";
279
280
281
282  /**
283   * The name of the field used to hold the search time limit in the JSON
284   * representation of this control.
285   */
286  @NotNull private static final String JSON_FIELD_TIME_LIMIT_SECONDS =
287       "time-limit-seconds";
288
289
290
291  /**
292   * The serial version UID for this serializable class.
293   */
294  private static final long serialVersionUID = -5261978490319320250L;
295
296
297
298  // The set of other select attributes from the user entry.
299  @NotNull private final List<Attribute> otherAttributes;
300
301  // The set of group DNs for the user.
302  @Nullable private final List<String> groupDNs;
303
304  // The set of privilege names for the user.
305  @Nullable private final List<String> privilegeNames;
306
307  // The custom idle time limit for the user.
308  @Nullable private final Long idleTimeLimitSeconds;
309
310  // The custom lookthrough limit for the user.
311  @Nullable private final Long lookthroughLimit;
312
313  // The custom size limit for the user.
314  @Nullable private final Long sizeLimit;
315
316  // The custom time limit for the user, in seconds.
317  @Nullable private final Long timeLimitSeconds;
318
319  // The name of the client connection policy selected for the user.
320  @Nullable private final String clientConnectionPolicyName;
321
322  // The DN of a user with equivalent authorization rights for use in servers
323  // in an entry-balancing environment in which the user's entry does not exist.
324  @Nullable private final String equivalentAuthzUserDN;
325
326
327
328  /**
329   * Creates a new empty control instance that is intended to be used only for
330   * decoding controls via the {@code DecodeableControl} interface.
331   */
332  GetUserResourceLimitsResponseControl()
333  {
334    otherAttributes            = null;
335    groupDNs                   = null;
336    privilegeNames             = null;
337    idleTimeLimitSeconds       = null;
338    lookthroughLimit           = null;
339    sizeLimit                  = null;
340    timeLimitSeconds           = null;
341    clientConnectionPolicyName = null;
342    equivalentAuthzUserDN      = null;
343  }
344
345
346
347  /**
348   * Creates a new get user resource limits response control with the provided
349   * information.
350   *
351   * @param  sizeLimit                   The custom size limit for the user.
352   *                                     It may be less than or equal to zero
353   *                                     if no size limit should be enforced for
354   *                                     the user.  It may be {@code null} if
355   *                                     there is no custom size limit or it is
356   *                                     not to be included in the control.
357   * @param  timeLimitSeconds            The custom time limit for the user, in
358   *                                     seconds.  It may be less than or equal
359   *                                     to zero if no time limit should be
360   *                                     enforced for the user.  It may be
361   *                                     {@code null} if there is no custom time
362   *                                     limit or it is not to be included in
363   *                                     the control.
364   * @param  idleTimeLimitSeconds        The custom idle time limit for the
365   *                                     user, in seconds.  It may be less than
366   *                                     or equal to zero if no idle time limit
367   *                                     should be enforced for the user.  It
368   *                                     may be {@code null} if there is no
369   *                                     custom idle time limit or it is not to
370   *                                     be included in the control.
371   * @param  lookthroughLimit            The custom lookthrough limit for the
372   *                                     user.  It may be less than or equal to
373   *                                     zero if no lookthrough limit should
374   *                                     be enforced for the user.  It may be
375   *                                     {@code null} if there is no custom
376   *                                     lookthrough limit for the user or it is
377   *                                     not to be included in the control.
378   * @param  equivalentAuthzUserDN       The DN of a user with equivalent
379   *                                     authorization rights for use in servers
380   *                                     in an entry-balancing environment in
381   *                                     which the user's entry does not exist.
382   *                                     It may be an empty string if the
383   *                                     equivalent authorization should be
384   *                                     anonymous, or {@code null} if there is
385   *                                     no custom equivalent authorization user
386   *                                     DN or it is not to be included in the
387   *                                     control.
388   * @param  clientConnectionPolicyName  The name of the client connection
389   *                                     policy that has been assigned to the
390   *                                     user, or {@code null} if the client
391   *                                     connection policy name is not to be
392   *                                     included in the control.
393   */
394  public GetUserResourceLimitsResponseControl(@Nullable final Long sizeLimit,
395              @Nullable final Long timeLimitSeconds,
396              @Nullable final Long idleTimeLimitSeconds,
397              @Nullable final Long lookthroughLimit,
398              @Nullable final String equivalentAuthzUserDN,
399              @Nullable final String clientConnectionPolicyName)
400  {
401    this(sizeLimit, timeLimitSeconds, idleTimeLimitSeconds, lookthroughLimit,
402         equivalentAuthzUserDN, clientConnectionPolicyName, null, null, null);
403  }
404
405
406
407  /**
408   * Creates a new get user resource limits response control with the provided
409   * information.
410   *
411   * @param  sizeLimit                   The custom size limit for the user.
412   *                                     It may be less than or equal to zero
413   *                                     if no size limit should be enforced for
414   *                                     the user.  It may be {@code null} if
415   *                                     there is no custom size limit or it is
416   *                                     not to be included in the control.
417   * @param  timeLimitSeconds            The custom time limit for the user, in
418   *                                     seconds.  It may be less than or equal
419   *                                     to zero if no time limit should be
420   *                                     enforced for the user.  It may be
421   *                                     {@code null} if there is no custom time
422   *                                     limit or it is not to be included in
423   *                                     the control.
424   * @param  idleTimeLimitSeconds        The custom idle time limit for the
425   *                                     user, in seconds.  It may be less than
426   *                                     or equal to zero if no idle time limit
427   *                                     should be enforced for the user.  It
428   *                                     may be {@code null} if there is no
429   *                                     custom idle time limit or it is not to
430   *                                     be included in the control.
431   * @param  lookthroughLimit            The custom lookthrough limit for the
432   *                                     user.  It may be less than or equal to
433   *                                     zero if no lookthrough limit should
434   *                                     be enforced for the user.  It may be
435   *                                     {@code null} if there is no custom
436   *                                     lookthrough limit for the user or it is
437   *                                     not to be included in the control.
438   * @param  equivalentAuthzUserDN       The DN of a user with equivalent
439   *                                     authorization rights for use in servers
440   *                                     in an entry-balancing environment in
441   *                                     which the user's entry does not exist.
442   *                                     It may be an empty string if the
443   *                                     equivalent authorization should be
444   *                                     anonymous, or {@code null} if there is
445   *                                     no custom equivalent authorization user
446   *                                     DN or it is not to be included in the
447   *                                     control.
448   * @param  clientConnectionPolicyName  The name of the client connection
449   *                                     policy that has been assigned to the
450   *                                     user, or {@code null} if the client
451   *                                     connection policy name is not to be
452   *                                     included in the control.
453   * @param  groupDNs                    The DNs of the groups in which the user
454   *                                     is a member.  It may be {@code null} if
455   *                                     group membership is not known, or
456   *                                     empty if the user isn't a member of any
457   *                                     groups.
458   * @param  privilegeNames              The names of the privileges assigned to
459   *                                     the user.  It may be {@code null} if
460   *                                     the privilege names are not known, or
461   *                                     empty if the  user doesn't have any
462   *                                     privileges.
463   * @param  otherAttributes             A set of additional attributes from the
464   *                                     user's entry.  It may be {@code null}
465   *                                     or empty if no additional attributes
466   *                                     are needed.
467   */
468  public GetUserResourceLimitsResponseControl(@Nullable final Long sizeLimit,
469              @Nullable final Long timeLimitSeconds,
470              @Nullable final Long idleTimeLimitSeconds,
471              @Nullable final Long lookthroughLimit,
472              @Nullable final String equivalentAuthzUserDN,
473              @Nullable final String clientConnectionPolicyName,
474              @Nullable final List<String> groupDNs,
475              @Nullable final List<String> privilegeNames,
476              @Nullable final List<Attribute> otherAttributes)
477  {
478    super(GET_USER_RESOURCE_LIMITS_RESPONSE_OID, false,
479         encodeValue(sizeLimit, timeLimitSeconds, idleTimeLimitSeconds,
480              lookthroughLimit, equivalentAuthzUserDN,
481              clientConnectionPolicyName, groupDNs, privilegeNames,
482              otherAttributes));
483
484    if ((sizeLimit == null) || (sizeLimit > 0L))
485    {
486      this.sizeLimit = sizeLimit;
487    }
488    else
489    {
490      this.sizeLimit = -1L;
491    }
492
493    if ((timeLimitSeconds == null) || (timeLimitSeconds > 0L))
494    {
495      this.timeLimitSeconds = timeLimitSeconds;
496    }
497    else
498    {
499      this.timeLimitSeconds = -1L;
500    }
501
502    if ((idleTimeLimitSeconds == null) || (idleTimeLimitSeconds > 0L))
503    {
504      this.idleTimeLimitSeconds = idleTimeLimitSeconds;
505    }
506    else
507    {
508      this.idleTimeLimitSeconds = -1L;
509    }
510
511    if ((lookthroughLimit == null) || (lookthroughLimit > 0L))
512    {
513      this.lookthroughLimit = lookthroughLimit;
514    }
515    else
516    {
517      this.lookthroughLimit = -1L;
518    }
519
520    this.equivalentAuthzUserDN      = equivalentAuthzUserDN;
521    this.clientConnectionPolicyName = clientConnectionPolicyName;
522
523    if (groupDNs == null)
524    {
525      this.groupDNs = null;
526    }
527    else
528    {
529      this.groupDNs =
530           Collections.unmodifiableList(new ArrayList<>(groupDNs));
531    }
532
533    if (privilegeNames == null)
534    {
535      this.privilegeNames = null;
536    }
537    else
538    {
539      this.privilegeNames =
540           Collections.unmodifiableList(new ArrayList<>(privilegeNames));
541    }
542
543    if (otherAttributes == null)
544    {
545      this.otherAttributes = Collections.emptyList();
546    }
547    else
548    {
549      this.otherAttributes =
550           Collections.unmodifiableList(new ArrayList<>(otherAttributes));
551    }
552  }
553
554
555
556  /**
557   * Encodes the provided information into an octet string suitable for use as
558   * the value of a get user resource limits response control.
559   *
560   * @param  sizeLimit                   The custom size limit for the user.
561   *                                     It may be less than or equal to zero
562   *                                     if no size limit should be enforced for
563   *                                     the user.  It may be {@code null} if
564   *                                     there is no custom size limit or it is
565   *                                     not to be included in the control.
566   * @param  timeLimitSeconds            The custom time limit for the user, in
567   *                                     seconds.  It may be less than or equal
568   *                                     to zero if no time limit should be
569   *                                     enforced for the user.  It may be
570   *                                     {@code null} if there is no custom time
571   *                                     limit or it is not to be included in
572   *                                     the control.
573   * @param  idleTimeLimitSeconds        The custom idle time limit for the
574   *                                     user, in seconds.  It may be less than
575   *                                     or equal to zero if no idle time limit
576   *                                     should be enforced for the user.  It
577   *                                     may be {@code null} if there is no
578   *                                     custom idle time limit or it is not to
579   *                                     be included in the control.
580   * @param  lookthroughLimit            The custom lookthrough limit for the
581   *                                     user.  It may be less than or equal to
582   *                                     zero if no lookthrough limit should
583   *                                     be enforced for the user.  It may be
584   *                                     {@code null} if there is no custom
585   *                                     lookthrough limit for the user or it is
586   *                                     not to be included in the control.
587   * @param  equivalentAuthzUserDN       The DN of a user with equivalent
588   *                                     authorization rights for use in servers
589   *                                     in an entry-balancing environment in
590   *                                     which the user's entry does not exist.
591   * @param  clientConnectionPolicyName  The name of the client connection
592   *                                     policy that has been assigned to the
593   *                                     user, or {@code null} if the client
594   *                                     connection policy name is not to be
595   *                                     included in the control.
596   * @param  groupDNs                    The DNs of the groups in which the user
597   *                                     is a member.  It may be {@code null} if
598   *                                     group membership is not known, or
599   *                                     empty if the user isn't a member of any
600   *                                     groups.
601   * @param  privilegeNames              The names of the privileges assigned to
602   *                                     the user.  It may be {@code null} if
603   *                                     the privilege names are not known, or
604   *                                     empty if the  user doesn't have any
605   *                                     privileges.
606   * @param  otherAttributes             A set of additional attributes from the
607   *                                     user's entry.  It may be {@code null}
608   *                                     or empty if no additional attributes
609   *                                     are needed.
610   *
611   * @return  The octet string which may be used as the value of a get user
612   *          resource limits response control
613   */
614  @NotNull()
615  private static ASN1OctetString encodeValue(@Nullable final Long sizeLimit,
616              @Nullable final Long timeLimitSeconds,
617              @Nullable final Long idleTimeLimitSeconds,
618              @Nullable final Long lookthroughLimit,
619              @Nullable final String equivalentAuthzUserDN,
620              @Nullable final String clientConnectionPolicyName,
621              @Nullable final List<String> groupDNs,
622              @Nullable final List<String> privilegeNames,
623              @Nullable final List<Attribute> otherAttributes)
624  {
625    final ArrayList<ASN1Element> elements = new ArrayList<>(10);
626
627    if (sizeLimit != null)
628    {
629      if (sizeLimit > 0L)
630      {
631        elements.add(new ASN1Long(TYPE_SIZE_LIMIT, sizeLimit));
632      }
633      else
634      {
635        elements.add(new ASN1Long(TYPE_SIZE_LIMIT, -1L));
636      }
637    }
638
639    if (timeLimitSeconds != null)
640    {
641      if (timeLimitSeconds > 0L)
642      {
643        elements.add(new ASN1Long(TYPE_TIME_LIMIT, timeLimitSeconds));
644      }
645      else
646      {
647        elements.add(new ASN1Long(TYPE_TIME_LIMIT, -1L));
648      }
649    }
650
651    if (idleTimeLimitSeconds != null)
652    {
653      if (idleTimeLimitSeconds > 0L)
654      {
655        elements.add(new ASN1Long(TYPE_IDLE_TIME_LIMIT, idleTimeLimitSeconds));
656      }
657      else
658      {
659        elements.add(new ASN1Long(TYPE_IDLE_TIME_LIMIT, -1L));
660      }
661    }
662
663    if (lookthroughLimit != null)
664    {
665      if (lookthroughLimit > 0L)
666      {
667        elements.add(new ASN1Long(TYPE_LOOKTHROUGH_LIMIT, lookthroughLimit));
668      }
669      else
670      {
671        elements.add(new ASN1Long(TYPE_LOOKTHROUGH_LIMIT, -1L));
672      }
673    }
674
675    if (equivalentAuthzUserDN != null)
676    {
677      elements.add(new ASN1OctetString(TYPE_EQUIVALENT_AUTHZ_USER_DN,
678           equivalentAuthzUserDN));
679    }
680
681    if (clientConnectionPolicyName != null)
682    {
683      elements.add(new ASN1OctetString(TYPE_CLIENT_CONNECTION_POLICY_NAME,
684           clientConnectionPolicyName));
685    }
686
687    if (groupDNs != null)
688    {
689      final ArrayList<ASN1Element> dnElements =
690           new ArrayList<>(groupDNs.size());
691      for (final String s : groupDNs)
692      {
693        dnElements.add(new ASN1OctetString(s));
694      }
695
696      elements.add(new ASN1Set(TYPE_GROUP_DNS, dnElements));
697    }
698
699    if (privilegeNames != null)
700    {
701      final ArrayList<ASN1Element> privElements =
702           new ArrayList<>(privilegeNames.size());
703      for (final String s : privilegeNames)
704      {
705        privElements.add(new ASN1OctetString(s));
706      }
707
708      elements.add(new ASN1Set(TYPE_PRIVILEGE_NAMES, privElements));
709    }
710
711    if ((otherAttributes != null) && (! otherAttributes.isEmpty()))
712    {
713      final ArrayList<ASN1Element> attrElements =
714           new ArrayList<>(otherAttributes.size());
715      for (final Attribute a : otherAttributes)
716      {
717        attrElements.add(a.encode());
718      }
719
720      elements.add(new ASN1Sequence(TYPE_OTHER_ATTRIBUTES, attrElements));
721    }
722
723    return new ASN1OctetString(new ASN1Sequence(elements).encode());
724  }
725
726
727
728  /**
729   * Creates a new get user resource limits response control decoded from the
730   * given generic control contents.
731   *
732   * @param  oid         The OID for the control.
733   * @param  isCritical  Indicates whether this control should be marked
734   *                     critical.
735   * @param  value       The value for the control.  It may be {@code null} if
736   *                     the control to decode does not have a value.
737   *
738   * @throws  LDAPException  If a problem occurs while attempting to decode the
739   *                         generic control as a get user resource limits
740   *                         response control.
741   */
742  public GetUserResourceLimitsResponseControl(@NotNull final String oid,
743              final boolean isCritical,
744              @Nullable final ASN1OctetString value)
745         throws LDAPException
746  {
747    super(oid, isCritical, value);
748
749    if (value == null)
750    {
751      throw new LDAPException(ResultCode.DECODING_ERROR,
752           ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_MISSING_VALUE.get());
753    }
754
755
756    List<Attribute> oa   = Collections.emptyList();
757    List<String>    gd   = null;
758    List<String>    pn   = null;
759    Long            sL   = null;
760    Long            tL   = null;
761    Long            iTL  = null;
762    Long            lL   = null;
763    String          eAUD = null;
764    String          cCPN = null;
765
766    try
767    {
768      final ASN1Element[] elements =
769           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
770      for (final ASN1Element e : elements)
771      {
772        switch (e.getType())
773        {
774          case TYPE_SIZE_LIMIT:
775            sL = ASN1Long.decodeAsLong(e).longValue();
776            break;
777          case TYPE_TIME_LIMIT:
778            tL = ASN1Long.decodeAsLong(e).longValue();
779            break;
780          case TYPE_IDLE_TIME_LIMIT:
781            iTL = ASN1Long.decodeAsLong(e).longValue();
782            break;
783          case TYPE_LOOKTHROUGH_LIMIT:
784            lL = ASN1Long.decodeAsLong(e).longValue();
785            break;
786          case TYPE_EQUIVALENT_AUTHZ_USER_DN:
787            eAUD = ASN1OctetString.decodeAsOctetString(e).stringValue();
788            break;
789          case TYPE_CLIENT_CONNECTION_POLICY_NAME:
790            cCPN = ASN1OctetString.decodeAsOctetString(e).stringValue();
791            break;
792          case TYPE_GROUP_DNS:
793            final ASN1Element[] groupElements =
794                 ASN1Set.decodeAsSet(e).elements();
795            gd = new ArrayList<>(groupElements.length);
796            for (final ASN1Element pe : groupElements)
797            {
798              gd.add(ASN1OctetString.decodeAsOctetString(pe).stringValue());
799            }
800            gd = Collections.unmodifiableList(gd);
801            break;
802          case TYPE_PRIVILEGE_NAMES:
803            final ASN1Element[] privElements =
804                 ASN1Set.decodeAsSet(e).elements();
805            pn = new ArrayList<>(privElements.length);
806            for (final ASN1Element pe : privElements)
807            {
808              pn.add(ASN1OctetString.decodeAsOctetString(pe).stringValue());
809            }
810            pn = Collections.unmodifiableList(pn);
811            break;
812          case TYPE_OTHER_ATTRIBUTES:
813            final ASN1Element[] attrElemnets =
814                 ASN1Sequence.decodeAsSequence(e).elements();
815            oa = new ArrayList<>(attrElemnets.length);
816            for (final ASN1Element ae : attrElemnets)
817            {
818              oa.add(Attribute.decode(ASN1Sequence.decodeAsSequence(ae)));
819            }
820            oa = Collections.unmodifiableList(oa);
821            break;
822          default:
823            // No action will be taken.  It may be the case that a future
824            // version of the control could return additional information.
825            break;
826        }
827      }
828    }
829    catch (final Exception e)
830    {
831      Debug.debugException(e);
832      throw new LDAPException(ResultCode.DECODING_ERROR,
833           ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_CANNOT_DECODE_VALUE.get(
834                StaticUtils.getExceptionMessage(e)),
835           e);
836    }
837
838    otherAttributes            = oa;
839    groupDNs                   = gd;
840    privilegeNames             = pn;
841    sizeLimit                  = sL;
842    timeLimitSeconds           = tL;
843    idleTimeLimitSeconds       = iTL;
844    lookthroughLimit           = lL;
845    equivalentAuthzUserDN      = eAUD;
846    clientConnectionPolicyName = cCPN;
847  }
848
849
850
851  /**
852   * {@inheritDoc}
853   */
854  @Override()
855  @NotNull()
856  public GetUserResourceLimitsResponseControl decodeControl(
857              @NotNull final String oid,
858              final boolean isCritical,
859              @Nullable final ASN1OctetString value)
860         throws LDAPException
861  {
862    return new GetUserResourceLimitsResponseControl(oid, isCritical, value);
863  }
864
865
866
867  /**
868   * Extracts a get user resource limits response control from the provided
869   * result.
870   *
871   * @param  result  The bind result from which to retrieve the get user
872   *                 resource limits response control.
873   *
874   * @return  The get user resource limits response control contained in the
875   *          provided result, or {@code null} if the result did not contain a
876   *          get user resource limits response control.
877   *
878   * @throws  LDAPException  If a problem is encountered while attempting to
879   *                         decode the get user resource limits response
880   *                         control contained in the provided result.
881   */
882  @Nullable()
883  public static GetUserResourceLimitsResponseControl get(
884                     @NotNull final BindResult result)
885         throws LDAPException
886  {
887    final Control c =
888         result.getResponseControl(GET_USER_RESOURCE_LIMITS_RESPONSE_OID);
889    if (c == null)
890    {
891      return null;
892    }
893
894    if (c instanceof GetUserResourceLimitsResponseControl)
895    {
896      return (GetUserResourceLimitsResponseControl) c;
897    }
898    else
899    {
900      return new GetUserResourceLimitsResponseControl(c.getOID(),
901           c.isCritical(), c.getValue());
902    }
903  }
904
905
906
907  /**
908   * Retrieves the custom size limit for the user, if available.
909   *
910   * @return  The custom size limit for the user, -1 if no size limit should be
911   *          enforced for the user, or {@code null} if no custom size limit
912   *          was included in the control.
913   */
914  @Nullable()
915  public Long getSizeLimit()
916  {
917    return sizeLimit;
918  }
919
920
921
922  /**
923   * Retrieves the custom time limit for the user in seconds, if available.
924   *
925   * @return  The custom time limit for the user in seconds, -1 if no time limit
926   *          should be enforced for the user, or {@code null} if no custom time
927   *          limit was included in the control.
928   */
929  @Nullable()
930  public Long getTimeLimitSeconds()
931  {
932    return timeLimitSeconds;
933  }
934
935
936
937  /**
938   * Retrieves the custom idle time limit for the user in seconds, if available.
939   *
940   * @return  The custom idle time limit for the user in seconds, -1 if no idle
941   *          time limit should be enforced for the user, or {@code null} if no
942   *          custom idle time limit was included in the control.
943   */
944  @Nullable()
945  public Long getIdleTimeLimitSeconds()
946  {
947    return idleTimeLimitSeconds;
948  }
949
950
951
952  /**
953   * Retrieves the custom lookthrough limit for the user, if available.
954   *
955   * @return  The custom lookthrough limit for the user, -1 if no lookthrough
956   *          limit should be enforced for the user, or {@code null} if no
957   *          custom lookthrough limit was included in the control.
958   */
959  @Nullable()
960  public Long getLookthroughLimit()
961  {
962    return lookthroughLimit;
963  }
964
965
966
967  /**
968   * Retrieves the equivalent authorization user DN, for use in servers in an
969   * entry-balancing environment in which the user's entry does not exist.
970   *
971   * @return  The equivalent authorization user DN for the user, an empty string
972   *          if the equivalent authorization is anonymous, or {@code null} if
973   *          no equivalent authorization user DN was included in the control.
974   */
975  @Nullable()
976  public String getEquivalentAuthzUserDN()
977  {
978    return equivalentAuthzUserDN;
979  }
980
981
982
983  /**
984   * Retrieves the name of the client connection policy that has been assigned
985   * to the user, if available.
986   *
987   * @return  The name of the client connection policy that has been assigned to
988   *          the user, or {@code null} if the client connection policy name was
989   *          not included in the control.
990   */
991  @Nullable()
992  public String getClientConnectionPolicyName()
993  {
994    return clientConnectionPolicyName;
995  }
996
997
998
999  /**
1000   * Retrieves the DNs of any groups in which the user is a member.
1001   *
1002   * @return  The DNs of any groups in which the user is a member, an empty list
1003   *          if the user is not a member of any groups, or {@code null} if the
1004   *           set of group DNs is not known.
1005   */
1006  @Nullable()
1007  public List<String> getGroupDNs()
1008  {
1009    return groupDNs;
1010  }
1011
1012
1013
1014  /**
1015   * Retrieves the names of any privileges assigned to the user.
1016   *
1017   * @return  The names of any privileges assigned to the user, an empty list if
1018   *          the user is known to have no privileges, or {@code null} if the
1019   *          set of user privileges is not known.
1020   */
1021  @Nullable()
1022  public List<String> getPrivilegeNames()
1023  {
1024    return privilegeNames;
1025  }
1026
1027
1028
1029  /**
1030   * Retrieves a list containing additional attributes from the user's entry.
1031   *
1032   * @return  A list containing additional attributes from the user's entry, or
1033   *          an empty list if no additional attributes were provided.
1034   */
1035  @NotNull
1036  public List<Attribute> getOtherAttributes()
1037  {
1038    return otherAttributes;
1039  }
1040
1041
1042
1043  /**
1044   * Retrieves the "other" attribute with the specified name.
1045   *
1046   * @param  name  The name of the "other" attribute to retrieve.  It must not
1047   *               be {@code null}.
1048   *
1049   * @return  The "other" attribute with the specified name, or {@code null} if
1050   *          there is no such "other" attribute.
1051   */
1052  @Nullable()
1053  public Attribute getOtherAttribute(@NotNull final String name)
1054  {
1055    for (final Attribute a : otherAttributes)
1056    {
1057      if (a.getName().equalsIgnoreCase(name))
1058      {
1059        return a;
1060      }
1061    }
1062
1063    return null;
1064  }
1065
1066
1067
1068  /**
1069   * {@inheritDoc}
1070   */
1071  @Override()
1072  @NotNull()
1073  public String getControlName()
1074  {
1075    return INFO_CONTROL_NAME_GET_USER_RESOURCE_LIMITS_RESPONSE.get();
1076  }
1077
1078
1079
1080  /**
1081   * Retrieves a representation of this get user resource limits response
1082   * control as a JSON object.  The JSON object uses the following fields:
1083   * <UL>
1084   *   <LI>
1085   *     {@code oid} -- A mandatory string field whose value is the object
1086   *     identifier for this control.  For the get user resource limits response
1087   *     control, the OID is "1.3.6.1.4.1.30221.2.5.26".
1088   *   </LI>
1089   *   <LI>
1090   *     {@code control-name} -- An optional string field whose value is a
1091   *     human-readable name for this control.  This field is only intended for
1092   *     descriptive purposes, and when decoding a control, the {@code oid}
1093   *     field should be used to identify the type of control.
1094   *   </LI>
1095   *   <LI>
1096   *     {@code criticality} -- A mandatory Boolean field used to indicate
1097   *     whether this control is considered critical.
1098   *   </LI>
1099   *   <LI>
1100   *     {@code value-base64} -- An optional string field whose value is a
1101   *     base64-encoded representation of the raw value for this get user
1102   *     resource limits response control.  Exactly one of the
1103   *     {@code value-base64} and {@code value-json} fields must be present.
1104   *   </LI>
1105   *   <LI>
1106   *     {@code value-json} -- An optional JSON object field whose value is a
1107   *     user-friendly representation of the value for this get user resource
1108   *     limits response control.  Exactly one of the {@code value-base64} and
1109   *     {@code value-json} fields must be present, and if the
1110   *     {@code value-json} field is used, then it will use the following
1111   *     fields:
1112   *     <UL>
1113   *       <LI>
1114   *         {@code size-limit} -- An optional integer field whose value is the
1115   *         effective search size limit for the user.
1116   *       </LI>
1117   *       <LI>
1118   *         {@code time-limit-seconds} -- An optional integer field whose value
1119   *         is the effective search time limit (in seconds) for the user.
1120   *       </LI>
1121   *       <LI>
1122   *         {@code idle-time-limit-seconds} -- An optional integer field whose
1123   *         value is the effective idle time limit (in seconds) for the user.
1124   *       </LI>
1125   *       <LI>
1126   *         {@code lookthrough-limit} -- An optional integer field whose
1127   *         value is the maximum number of entries that the server may examine
1128   *         in the course of processing any single search operation for the
1129   *         user.
1130   *       </LI>
1131   *       <LI>
1132   *         {@code equivalent-authorization-user-dn} -- An optional string
1133   *         field whose value is the DN of a user entry that is meant to have
1134   *         roughly equivalent access control rights to the authenticated user.
1135   *       </LI>
1136   *       <LI>
1137   *         {@code client-connection-policy-name} -- An optional string field
1138   *         whose value is the name of the client connection policy that has
1139   *         been assigned to the client connection.
1140   *       </LI>
1141   *       <LI>
1142   *         {@code group-dns} -- An optional array field whose values are
1143   *         strings that represent the DNs of the groups in which the user is a
1144   *         member.
1145   *       </LI>
1146   *       <LI>
1147   *         {@code privilege-names} -- An optional array field whose values are
1148   *         strings that represent the names of the privileges assigned to the
1149   *         user.
1150   *       </LI>
1151   *       <LI>
1152   *         {@code other attributes} -- An optional array field whose values
1153   *         are JSON objects that represent additional attributes of note from
1154   *         the user's entry.  Each of these JSON objects will include the
1155   *         following fields:
1156   *         <UL>
1157   *           <LI>
1158   *             {@code name} -- A string field whose value is the name of the
1159   *             additional attribute.
1160   *           </LI>
1161   *           <LI>
1162   *             {@code values} -- An array field whose values are strings
1163   *             that represent the values for the attribute.
1164   *           </LI>
1165   *         </UL>
1166   *       </LI>
1167   *     </UL>
1168   *   </LI>
1169   * </UL>
1170   *
1171   * @return  A JSON object that contains a representation of this control.
1172   */
1173  @Override()
1174  @NotNull()
1175  public JSONObject toJSONControl()
1176  {
1177    final Map<String,JSONValue> valueFields = new LinkedHashMap<>();
1178
1179    if (sizeLimit != null)
1180    {
1181      valueFields.put(JSON_FIELD_SIZE_LIMIT, new JSONNumber(sizeLimit));
1182    }
1183
1184    if (timeLimitSeconds != null)
1185    {
1186      valueFields.put(JSON_FIELD_TIME_LIMIT_SECONDS,
1187           new JSONNumber(timeLimitSeconds));
1188    }
1189
1190    if (idleTimeLimitSeconds != null)
1191    {
1192      valueFields.put(JSON_FIELD_IDLE_TIME_LIMIT_SECONDS,
1193           new JSONNumber(idleTimeLimitSeconds));
1194    }
1195
1196    if (lookthroughLimit != null)
1197    {
1198      valueFields.put(JSON_FIELD_LOOKTHROUGH_LIMIT,
1199           new JSONNumber(lookthroughLimit));
1200    }
1201
1202    if (equivalentAuthzUserDN != null)
1203    {
1204      valueFields.put(JSON_FIELD_EQUIVALENT_AUTHZ_USER_DN,
1205           new JSONString(equivalentAuthzUserDN));
1206    }
1207
1208    if (clientConnectionPolicyName != null)
1209    {
1210      valueFields.put(JSON_FIELD_CLIENT_CONNECTION_POLICY_NAME,
1211           new JSONString(clientConnectionPolicyName));
1212    }
1213
1214    if (groupDNs != null)
1215    {
1216      final List<JSONValue> groupDNValues = new ArrayList<>(groupDNs.size());
1217      for (final String groupDN : groupDNs)
1218      {
1219        groupDNValues.add(new JSONString(groupDN));
1220      }
1221
1222      valueFields.put(JSON_FIELD_GROUP_DNS, new JSONArray(groupDNValues));
1223    }
1224
1225    if (privilegeNames != null)
1226    {
1227      final List<JSONValue> privilegeNameValues =
1228           new ArrayList<>(privilegeNames.size());
1229      for (final String privilegeName : privilegeNames)
1230      {
1231        privilegeNameValues.add(new JSONString(privilegeName));
1232      }
1233
1234      valueFields.put(JSON_FIELD_PRIVILEGE_NAMES,
1235           new JSONArray(privilegeNameValues));
1236    }
1237
1238    if ((otherAttributes != null) && (! otherAttributes.isEmpty()))
1239    {
1240      final List<JSONValue> otherAttributesValues =
1241           new ArrayList<>(otherAttributes.size());
1242      for (final Attribute a : otherAttributes)
1243      {
1244        final List<JSONValue> attributeValues = new ArrayList<>(a.size());
1245        for (final String value : a.getValues())
1246        {
1247          attributeValues.add(new JSONString(value));
1248        }
1249
1250        otherAttributesValues.add(new JSONObject(
1251             new JSONField(JSON_FIELD_ATTRIBUTE_NAME, a.getName()),
1252             new JSONField(JSON_FIELD_ATTRIBUTE_VALUES,
1253                  new JSONArray(attributeValues))));
1254      }
1255
1256      valueFields.put(JSON_FIELD_OTHER_ATTRIBUTES,
1257           new JSONArray(otherAttributesValues));
1258    }
1259
1260    return new JSONObject(
1261         new JSONField(JSONControlDecodeHelper.JSON_FIELD_OID,
1262              GET_USER_RESOURCE_LIMITS_RESPONSE_OID),
1263         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CONTROL_NAME,
1264              INFO_CONTROL_NAME_GET_USER_RESOURCE_LIMITS_RESPONSE.get()),
1265         new JSONField(JSONControlDecodeHelper.JSON_FIELD_CRITICALITY,
1266              isCritical()),
1267         new JSONField(JSONControlDecodeHelper.JSON_FIELD_VALUE_JSON,
1268              new JSONObject(valueFields)));
1269  }
1270
1271
1272
1273  /**
1274   * Attempts to decode the provided object as a JSON representation of a get
1275   * user resource limits response control.
1276   *
1277   * @param  controlObject  The JSON object to be decoded.  It must not be
1278   *                        {@code null}.
1279   * @param  strict         Indicates whether to use strict mode when decoding
1280   *                        the provided JSON object.  If this is {@code true},
1281   *                        then this method will throw an exception if the
1282   *                        provided JSON object contains any unrecognized
1283   *                        fields.  If this is {@code false}, then unrecognized
1284   *                        fields will be ignored.
1285   *
1286   * @return  The get user resource limits response control that was decoded
1287   *          from the provided JSON object.
1288   *
1289   * @throws  LDAPException  If the provided JSON object cannot be parsed as a
1290   *                         valid get user resource limits response control.
1291   */
1292  @NotNull()
1293  public static GetUserResourceLimitsResponseControl decodeJSONControl(
1294              @NotNull final JSONObject controlObject,
1295              final boolean strict)
1296         throws LDAPException
1297  {
1298    final JSONControlDecodeHelper jsonControl = new JSONControlDecodeHelper(
1299         controlObject, strict, true, true);
1300
1301    final ASN1OctetString rawValue = jsonControl.getRawValue();
1302    if (rawValue != null)
1303    {
1304      return new GetUserResourceLimitsResponseControl(jsonControl.getOID(),
1305           jsonControl.getCriticality(), rawValue);
1306    }
1307
1308
1309    final JSONObject valueObject = jsonControl.getValueObject();
1310
1311    final Long sizeLimit = valueObject.getFieldAsLong(JSON_FIELD_SIZE_LIMIT);
1312    final Long timeLimitSeconds =
1313         valueObject.getFieldAsLong(JSON_FIELD_TIME_LIMIT_SECONDS);
1314    final Long idleTimeLimitSeconds =
1315         valueObject.getFieldAsLong(JSON_FIELD_IDLE_TIME_LIMIT_SECONDS);
1316    final Long lookthroughLimit =
1317         valueObject.getFieldAsLong(JSON_FIELD_LOOKTHROUGH_LIMIT);
1318    final String equivalentAuthZUserDN =
1319         valueObject.getFieldAsString(JSON_FIELD_EQUIVALENT_AUTHZ_USER_DN);
1320    final String clientConnectionPolicyName =
1321         valueObject.getFieldAsString(JSON_FIELD_CLIENT_CONNECTION_POLICY_NAME);
1322
1323    final List<String> groupDNs;
1324    final List<JSONValue> groupDNValues =
1325         valueObject.getFieldAsArray(JSON_FIELD_GROUP_DNS);
1326    if (groupDNValues == null)
1327    {
1328      groupDNs = null;
1329    }
1330    else
1331    {
1332      groupDNs = new ArrayList<>(groupDNValues.size());
1333      for (final JSONValue v : groupDNValues)
1334      {
1335        if (v instanceof JSONString)
1336        {
1337          groupDNs.add(((JSONString) v).stringValue());
1338        }
1339        else
1340        {
1341          throw new LDAPException(ResultCode.DECODING_ERROR,
1342               ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_ARRAY_VALUE_NOT_STRING
1343                    .get(controlObject.toSingleLineString(),
1344                         JSON_FIELD_GROUP_DNS));
1345        }
1346      }
1347    }
1348
1349    final List<String> privilegeNames;
1350    final List<JSONValue> privilegeNameValues =
1351         valueObject.getFieldAsArray(JSON_FIELD_PRIVILEGE_NAMES);
1352    if (privilegeNameValues == null)
1353    {
1354      privilegeNames = null;
1355    }
1356    else
1357    {
1358      privilegeNames = new ArrayList<>(privilegeNameValues.size());
1359      for (final JSONValue v : privilegeNameValues)
1360      {
1361        if (v instanceof JSONString)
1362        {
1363          privilegeNames.add(((JSONString) v).stringValue());
1364        }
1365        else
1366        {
1367          throw new LDAPException(ResultCode.DECODING_ERROR,
1368               ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_ARRAY_VALUE_NOT_STRING
1369                    .get(controlObject.toSingleLineString(),
1370                         JSON_FIELD_PRIVILEGE_NAMES));
1371        }
1372      }
1373    }
1374
1375
1376    final List<Attribute> otherAttributes = new ArrayList<>();
1377    final List<JSONValue> otherAttributeValues =
1378         valueObject.getFieldAsArray(JSON_FIELD_OTHER_ATTRIBUTES);
1379    if (otherAttributeValues != null)
1380    {
1381      for (final JSONValue otherAttributeValue : otherAttributeValues)
1382      {
1383        if (otherAttributeValue instanceof JSONObject)
1384        {
1385          final JSONObject o = (JSONObject) otherAttributeValue;
1386
1387          final String name = o.getFieldAsString(JSON_FIELD_ATTRIBUTE_NAME);
1388          if (name == null)
1389          {
1390            throw new LDAPException(ResultCode.DECODING_ERROR,
1391                 ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_MISSING_ATTR_FIELD.
1392                      get(controlObject.toSingleLineString(),
1393                           JSON_FIELD_OTHER_ATTRIBUTES,
1394                           JSON_FIELD_ATTRIBUTE_NAME));
1395          }
1396
1397          final List<JSONValue> valueValues =
1398               o.getFieldAsArray(JSON_FIELD_ATTRIBUTE_VALUES);
1399          if (valueValues == null)
1400          {
1401            throw new LDAPException(ResultCode.DECODING_ERROR,
1402                 ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_MISSING_ATTR_FIELD.
1403                      get(controlObject.toSingleLineString(),
1404                           JSON_FIELD_OTHER_ATTRIBUTES,
1405                           JSON_FIELD_ATTRIBUTE_VALUES));
1406          }
1407
1408          final List<String> values = new ArrayList<>(valueValues.size());
1409          for (final JSONValue v : valueValues)
1410          {
1411            if (v instanceof JSONString)
1412            {
1413              values.add(((JSONString) v).stringValue());
1414            }
1415            else
1416            {
1417              throw new LDAPException(ResultCode.DECODING_ERROR,
1418                   ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_VALUE_NOT_STRING.
1419                        get(controlObject.toSingleLineString(),
1420                             JSON_FIELD_OTHER_ATTRIBUTES,
1421                             JSON_FIELD_ATTRIBUTE_VALUES));
1422            }
1423          }
1424
1425          otherAttributes.add(new Attribute(name, values));
1426        }
1427        else
1428        {
1429          throw new LDAPException(ResultCode.DECODING_ERROR,
1430               ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_ATTR_NOT_OBJECT.get(
1431                    controlObject.toSingleLineString(),
1432                    JSON_FIELD_OTHER_ATTRIBUTES));
1433        }
1434      }
1435    }
1436
1437
1438    if (strict)
1439    {
1440      final List<String> unrecognizedFields =
1441           JSONControlDecodeHelper.getControlObjectUnexpectedFields(
1442                valueObject, JSON_FIELD_SIZE_LIMIT,
1443                JSON_FIELD_TIME_LIMIT_SECONDS,
1444                JSON_FIELD_IDLE_TIME_LIMIT_SECONDS,
1445                JSON_FIELD_TIME_LIMIT_SECONDS,
1446                JSON_FIELD_LOOKTHROUGH_LIMIT,
1447                JSON_FIELD_EQUIVALENT_AUTHZ_USER_DN,
1448                JSON_FIELD_CLIENT_CONNECTION_POLICY_NAME,
1449                JSON_FIELD_GROUP_DNS,
1450                JSON_FIELD_PRIVILEGE_NAMES,
1451                JSON_FIELD_OTHER_ATTRIBUTES);
1452      if (! unrecognizedFields.isEmpty())
1453      {
1454        throw new LDAPException(ResultCode.DECODING_ERROR,
1455             ERR_GET_USER_RESOURCE_LIMITS_RESPONSE_JSON_UNRECOGNIZED_FIELD.get(
1456                  controlObject.toSingleLineString(),
1457                  unrecognizedFields.get(0)));
1458      }
1459    }
1460
1461
1462    return new GetUserResourceLimitsResponseControl(sizeLimit,
1463         timeLimitSeconds, idleTimeLimitSeconds, lookthroughLimit,
1464         equivalentAuthZUserDN, clientConnectionPolicyName, groupDNs,
1465         privilegeNames, otherAttributes);
1466  }
1467
1468
1469
1470  /**
1471   * {@inheritDoc}
1472   */
1473  @Override()
1474  public void toString(@NotNull final StringBuilder buffer)
1475  {
1476    buffer.append("GetUserResourceLimitsResponseControl(");
1477
1478    boolean added = false;
1479    if (sizeLimit != null)
1480    {
1481      buffer.append("sizeLimit=");
1482      buffer.append(sizeLimit);
1483      added = true;
1484    }
1485
1486    if (timeLimitSeconds != null)
1487    {
1488      if (added)
1489      {
1490        buffer.append(", ");
1491      }
1492
1493      buffer.append("timeLimitSeconds=");
1494      buffer.append(timeLimitSeconds);
1495      added = true;
1496    }
1497
1498    if (idleTimeLimitSeconds != null)
1499    {
1500      if (added)
1501      {
1502        buffer.append(", ");
1503      }
1504
1505      buffer.append("idleTimeLimitSeconds=");
1506      buffer.append(idleTimeLimitSeconds);
1507      added = true;
1508    }
1509
1510    if (lookthroughLimit != null)
1511    {
1512      if (added)
1513      {
1514        buffer.append(", ");
1515      }
1516
1517      buffer.append("lookthroughLimit=");
1518      buffer.append(lookthroughLimit);
1519      added = true;
1520    }
1521
1522    if (equivalentAuthzUserDN != null)
1523    {
1524      if (added)
1525      {
1526        buffer.append(", ");
1527      }
1528
1529      buffer.append("equivalentAuthzUserDN=\"");
1530      buffer.append(equivalentAuthzUserDN);
1531      buffer.append('"');
1532      added = true;
1533    }
1534
1535    if (clientConnectionPolicyName != null)
1536    {
1537      if (added)
1538      {
1539        buffer.append(", ");
1540      }
1541
1542      buffer.append("clientConnectionPolicyName=\"");
1543      buffer.append(clientConnectionPolicyName);
1544      buffer.append('"');
1545      added = true;
1546    }
1547
1548    if (groupDNs != null)
1549    {
1550      if (added)
1551      {
1552        buffer.append(", ");
1553      }
1554
1555      buffer.append("groupDNs={");
1556
1557      final Iterator<String> dnIterator = groupDNs.iterator();
1558      while (dnIterator.hasNext())
1559      {
1560        buffer.append('"');
1561        buffer.append(dnIterator.next());
1562        buffer.append('"');
1563
1564        if (dnIterator.hasNext())
1565        {
1566          buffer.append(", ");
1567        }
1568      }
1569
1570      buffer.append('}');
1571      added = true;
1572    }
1573
1574    if (privilegeNames != null)
1575    {
1576      if (added)
1577      {
1578        buffer.append(", ");
1579      }
1580
1581      buffer.append("privilegeNames={");
1582
1583      final Iterator<String> privilegeIterator = privilegeNames.iterator();
1584      while (privilegeIterator.hasNext())
1585      {
1586        buffer.append('"');
1587        buffer.append(privilegeIterator.next());
1588        buffer.append('"');
1589
1590        if (privilegeIterator.hasNext())
1591        {
1592          buffer.append(", ");
1593        }
1594      }
1595
1596      buffer.append('}');
1597      added = true;
1598    }
1599
1600    if (! otherAttributes.isEmpty())
1601    {
1602      if (added)
1603      {
1604        buffer.append(", ");
1605      }
1606
1607      buffer.append("otherAttributes={");
1608
1609      final Iterator<Attribute> attrIterator = otherAttributes.iterator();
1610      while (attrIterator.hasNext())
1611      {
1612        attrIterator.next().toString(buffer);
1613
1614        if (attrIterator.hasNext())
1615        {
1616          buffer.append(", ");
1617        }
1618      }
1619
1620      buffer.append('}');
1621    }
1622
1623    buffer.append("')");
1624  }
1625}