001/*
002 * Copyright 2012-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2012-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) 2012-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.unboundidds.extensions;
037
038
039
040import java.util.ArrayList;
041import java.util.Collection;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.List;
045
046import com.unboundid.asn1.ASN1Element;
047import com.unboundid.asn1.ASN1Enumerated;
048import com.unboundid.asn1.ASN1OctetString;
049import com.unboundid.asn1.ASN1Sequence;
050import com.unboundid.ldap.sdk.Control;
051import com.unboundid.ldap.sdk.ExtendedRequest;
052import com.unboundid.ldap.sdk.LDAPException;
053import com.unboundid.ldap.sdk.ResultCode;
054import com.unboundid.util.Debug;
055import com.unboundid.util.NotMutable;
056import com.unboundid.util.NotNull;
057import com.unboundid.util.Nullable;
058import com.unboundid.util.StaticUtils;
059import com.unboundid.util.ThreadSafety;
060import com.unboundid.util.ThreadSafetyLevel;
061import com.unboundid.util.Validator;
062
063import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
064
065
066
067/**
068 * This class provides an implementation of an extended request that may be used
069 * to set the accessibility of one or more subtrees in the Ping Identity,
070 * UnboundID, or Nokia/Alcatel-Lucent 8661 Directory Server.  It may be used to
071 * indicate that a specified set of entries and all their subordinates should be
072 * invisible or read-only, or to restore it to full accessibility.
073 * <BR>
074 * <BLOCKQUOTE>
075 *   <B>NOTE:</B>  This class, and other classes within the
076 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
077 *   supported for use against Ping Identity, UnboundID, and
078 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
079 *   for proprietary functionality or for external specifications that are not
080 *   considered stable or mature enough to be guaranteed to work in an
081 *   interoperable way with other types of LDAP servers.
082 * </BLOCKQUOTE>
083 * <BR>
084 * The OID for this request is 1.3.6.1.4.1.30221.2.6.19, and the
085 * value must have the encoding specified below.  Note that the initial
086 * specification for this extended request only allowed for the specification of
087 * a single subtree, whereas it is now possible to affect the accessibility of
088 * multiple subtrees in a single request.  In order to preserve compatibility
089 * with the original encoding, if there is more than one target subtree, then
090 * the first subtree must be specified as the first element in the value
091 * sequence and the remaining subtrees must be specified in the
092 * additionalSubtreeBaseDNs element.
093 * <BR><BR>
094 * <PRE>
095 *   SetSubtreeAccessibilityRequestValue ::= SEQUENCE {
096 *        subtreeBaseDN                LDAPDN,
097 *        subtreeAccessibility         ENUMERATED {
098 *             accessible                 (0),
099 *             read-only-bind-allowed     (1),
100 *             read-only-bind-denied      (2),
101 *             hidden                     (3),
102 *             to-be-deleted              (4),
103 *             ... },
104 *        bypassUserDN                 [0] LDAPDN OPTIONAL,
105 *        additionalSubtreeBaseDNs     [1] SEQUENCE OF LDAPDN OPTIONAL,
106 *        ... }
107 * </PRE>
108 */
109@NotMutable()
110@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
111public final class SetSubtreeAccessibilityExtendedRequest
112       extends ExtendedRequest
113{
114  /**
115   * The OID (1.3.6.1.4.1.30221.2.6.19) for the set subtree accessibility
116   * extended request.
117   */
118  @NotNull public static final String SET_SUBTREE_ACCESSIBILITY_REQUEST_OID =
119       "1.3.6.1.4.1.30221.2.6.19";
120
121
122
123  /**
124   * The BER type for the bypass user DN element of the request.
125   */
126  private static final byte TYPE_BYPASS_USER_DN = (byte) 0x80;
127
128
129
130  /**
131   * The BER type for the set of additional subtree base DNs.
132   */
133  private static final byte TYPE_ADDITIONAL_SUBTREE_BASE_DNS = (byte) 0xA1;
134
135
136
137  /**
138   * The serial version UID for this serializable class.
139   */
140  private static final long serialVersionUID = -6619215987488239440L;
141
142
143
144  // The set of subtree base DNs included in the request.
145  @NotNull private final List<String> subtreeBaseDNs;
146
147  // The DN of a user who will be exempted from the restrictions.  This is not
148  // applicable for a subtree accessibility of ACCESSIBLE.
149  @Nullable private final String bypassUserDN;
150
151  // The accessibility state to use for the target subtrees.
152  @NotNull private final SubtreeAccessibilityState accessibilityState;
153
154
155
156  /**
157   * Creates a new set subtree accessibility extended request with the provided
158   * information.
159   *
160   * @param  subtreeBaseDNs      The set of base DNs for the target subtree.
161   *                             It must not be {@code null} or empty.
162   * @param  accessibilityState  The accessibility state to use for the target
163   *                             subtrees.
164   * @param  bypassUserDN        The DN of a user that will be allowed to bypass
165   *                             restrictions on the target subtrees.
166   * @param  controls            The set of controls to include in the request.
167   */
168  private SetSubtreeAccessibilityExtendedRequest(
169               @NotNull final Collection<String> subtreeBaseDNs,
170               @NotNull final SubtreeAccessibilityState accessibilityState,
171               @Nullable final String bypassUserDN,
172               @Nullable final Control... controls)
173  {
174    super(SET_SUBTREE_ACCESSIBILITY_REQUEST_OID,
175         encodeValue(subtreeBaseDNs, accessibilityState, bypassUserDN),
176         controls);
177
178    this.subtreeBaseDNs = Collections.unmodifiableList(
179         new ArrayList<>(subtreeBaseDNs));
180    this.accessibilityState = accessibilityState;
181    this.bypassUserDN = bypassUserDN;
182  }
183
184
185
186  /**
187   * Encodes the provided information for use as the extended request value.
188   *
189   * @param  subtreeBaseDNs      The set of base DNs for the target subtrees.
190   *                             It must not be {@code null} or empty.
191   * @param  accessibilityState  The accessibility state to use for the target
192   *                             subtrees.
193   * @param  bypassUserDN        The DN of a user that will be allowed to bypass
194   *                             restrictions on the target subtrees.
195   *
196   * @return  An ASN.1 octet string containing the encoded value.
197   */
198  @NotNull()
199  private static ASN1OctetString encodeValue(
200               @NotNull final Collection<String> subtreeBaseDNs,
201               @NotNull final SubtreeAccessibilityState accessibilityState,
202               @Nullable final String bypassUserDN)
203  {
204    final Iterator<String> dnIterator = subtreeBaseDNs.iterator();
205    final String subtreeBaseDN = dnIterator.next();
206    Validator.ensureNotNull(subtreeBaseDN);
207
208    final ArrayList<ASN1Element> elements = new ArrayList<>(4);
209    elements.add(new ASN1OctetString(subtreeBaseDN));
210    elements.add(new ASN1Enumerated(accessibilityState.intValue()));
211
212    if (bypassUserDN != null)
213    {
214      elements.add(new ASN1OctetString(TYPE_BYPASS_USER_DN, bypassUserDN));
215    }
216
217    if (dnIterator.hasNext())
218    {
219      final ArrayList<ASN1Element> additionalDNElements =
220           new ArrayList<>(subtreeBaseDNs.size()-1);
221      while (dnIterator.hasNext())
222      {
223        final String additionalDN = dnIterator.next();
224        Validator.ensureNotNull(additionalDN);
225        additionalDNElements.add(new ASN1OctetString(additionalDN));
226      }
227      elements.add(new ASN1Sequence(TYPE_ADDITIONAL_SUBTREE_BASE_DNS,
228           additionalDNElements));
229    }
230
231    return new ASN1OctetString(new ASN1Sequence(elements).encode());
232  }
233
234
235
236  /**
237   * Creates a new set subtree accessibility extended request from the provided
238   * generic extended request.
239   *
240   * @param  extendedRequest  The generic extended request to use to create this
241   *                          set subtree accessibility extended request.
242   *
243   * @throws  LDAPException  If a problem occurs while decoding the request.
244   */
245  public SetSubtreeAccessibilityExtendedRequest(
246              @NotNull final ExtendedRequest extendedRequest)
247         throws LDAPException
248  {
249    super(extendedRequest);
250
251    final ASN1OctetString value = extendedRequest.getValue();
252    if (value == null)
253    {
254      throw new LDAPException(ResultCode.DECODING_ERROR,
255           ERR_SET_SUBTREE_ACCESSIBILITY_NO_VALUE.get());
256    }
257
258    try
259    {
260      final ASN1Element[] elements =
261           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
262
263      final List<String> baseDNs = new ArrayList<>(10);
264      baseDNs.add(ASN1OctetString.decodeAsOctetString(
265           elements[0]).stringValue());
266
267      final int accessibilityStateValue =
268           ASN1Enumerated.decodeAsEnumerated(elements[1]).intValue();
269      accessibilityState =
270           SubtreeAccessibilityState.valueOf(accessibilityStateValue);
271      if (accessibilityState == null)
272      {
273        throw new LDAPException(ResultCode.DECODING_ERROR,
274             ERR_SET_SUBTREE_ACCESSIBILITY_INVALID_ACCESSIBILITY_STATE.get(
275                  accessibilityStateValue));
276      }
277
278      String bypassDN = null;
279      for (int i=2; i < elements.length; i++)
280      {
281        switch (elements[i].getType())
282        {
283          case TYPE_BYPASS_USER_DN:
284            bypassDN =
285                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
286            break;
287
288          case TYPE_ADDITIONAL_SUBTREE_BASE_DNS:
289            for (final ASN1Element e :
290                 ASN1Sequence.decodeAsSequence(elements[i]).elements())
291            {
292              baseDNs.add(ASN1OctetString.decodeAsOctetString(e).stringValue());
293            }
294            break;
295
296          default:
297            throw new LDAPException(ResultCode.DECODING_ERROR,
298                 ERR_SET_SUBTREE_ACCESSIBILITY_INVALID_ELEMENT_TYPE.get(
299                      StaticUtils.toHex(elements[i].getType())));
300        }
301      }
302      bypassUserDN = bypassDN;
303      subtreeBaseDNs = Collections.unmodifiableList(baseDNs);
304    }
305    catch (final LDAPException le)
306    {
307      Debug.debugException(le);
308      throw le;
309    }
310    catch (final Exception e)
311    {
312      Debug.debugException(e);
313      throw new LDAPException(ResultCode.DECODING_ERROR,
314           ERR_SET_SUBTREE_ACCESSIBILITY_CANNOT_DECODE.get(
315                StaticUtils.getExceptionMessage(e)),
316           e);
317    }
318
319
320    if ((accessibilityState == SubtreeAccessibilityState.ACCESSIBLE) &&
321        (bypassUserDN != null))
322    {
323      throw new LDAPException(ResultCode.DECODING_ERROR,
324           ERR_SET_SUBTREE_ACCESSIBILITY_UNEXPECTED_BYPASS_DN.get(
325                accessibilityState.getStateName()));
326    }
327
328    if ((accessibilityState == SubtreeAccessibilityState.TO_BE_DELETED) &&
329         (bypassUserDN == null))
330    {
331      throw new LDAPException(ResultCode.DECODING_ERROR,
332           ERR_SET_SUBTREE_ACCESSIBILITY_MISSING_BYPASS_DN.get(
333                accessibilityState.getStateName()));
334    }
335  }
336
337
338
339  /**
340   * Creates a new set subtree accessibility extended request that will make the
341   * specified subtree accessible.
342   *
343   * @param  subtreeBaseDN  The base DN for the subtree to make accessible.  It
344   *                        must not be {@code null}.
345   * @param  controls       The set of controls to include in the request.  It
346   *                        may be {@code null} or empty if no controls are
347   *                        needed.
348   *
349   * @return  The set subtree accessibility extended request that was created.
350   */
351  @NotNull()
352  public static SetSubtreeAccessibilityExtendedRequest
353              createSetAccessibleRequest(@NotNull final String subtreeBaseDN,
354                                         @Nullable final Control... controls)
355  {
356    Validator.ensureNotNull(subtreeBaseDN);
357
358    return new SetSubtreeAccessibilityExtendedRequest(
359         Collections.singletonList(subtreeBaseDN),
360         SubtreeAccessibilityState.ACCESSIBLE, null, controls);
361  }
362
363
364
365  /**
366   * Creates a new set subtree accessibility extended request that will make the
367   * specified subtrees accessible.
368   *
369   * @param  subtreeBaseDNs  The base DNs for the subtrees to make accessible.
370   *                         It must not be {@code null} or empty.  If multiple
371   *                         base DNs are specified, then all must reside below
372   *                         the same backend base DN.
373   * @param  controls        The set of controls to include in the request.  It
374   *                         may be {@code null} or empty if no controls are
375   *                         needed.
376   *
377   * @return  The set subtree accessibility extended request that was created.
378   */
379  @NotNull()
380  public static SetSubtreeAccessibilityExtendedRequest
381                     createSetAccessibleRequest(
382                          @NotNull final Collection<String> subtreeBaseDNs,
383                          @Nullable final Control... controls)
384  {
385    Validator.ensureNotNull(subtreeBaseDNs);
386    Validator.ensureFalse(subtreeBaseDNs.isEmpty());
387
388    return new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
389         SubtreeAccessibilityState.ACCESSIBLE, null, controls);
390  }
391
392
393
394  /**
395   * Creates a new set subtree accessibility extended request that will make the
396   * specified subtree read-only.
397   *
398   * @param  subtreeBaseDN  The base DN for the subtree to make read-only.  It
399   *                        must not be {@code null}.
400   * @param  allowBind      Indicates whether users within the specified subtree
401   *                        will be allowed to bind.
402   * @param  bypassUserDN   The DN of a user that will be allowed to perform
403   *                        write (add, delete, modify, and modify DN)
404   *                        operations in the specified subtree.  It may be
405   *                        {@code null} if no bypass user is needed.
406   * @param  controls       The set of controls to include in the request.  It
407   *                        may be {@code null} or empty if no controls are
408   *                        needed.
409   *
410   * @return  The set subtree accessibility extended request that was created.
411   */
412  @NotNull()
413  public static SetSubtreeAccessibilityExtendedRequest
414              createSetReadOnlyRequest(@NotNull final String subtreeBaseDN,
415                                       final boolean allowBind,
416                                       @Nullable final String bypassUserDN,
417                                       @Nullable final Control... controls)
418  {
419    Validator.ensureNotNull(subtreeBaseDN);
420
421    if (allowBind)
422    {
423      return new SetSubtreeAccessibilityExtendedRequest(
424           Collections.singletonList(subtreeBaseDN),
425           SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED, bypassUserDN,
426           controls);
427    }
428    else
429    {
430      return new SetSubtreeAccessibilityExtendedRequest(
431           Collections.singletonList(subtreeBaseDN),
432           SubtreeAccessibilityState.READ_ONLY_BIND_DENIED, bypassUserDN,
433           controls);
434    }
435  }
436
437
438
439  /**
440   * Creates a new set subtree accessibility extended request that will make the
441   * specified subtrees read-only.
442   *
443   * @param  subtreeBaseDNs  The base DNs for the subtrees to make read-only.
444   *                         It must not be {@code null} or empty.  If multiple
445   *                         base DNs are specified, then all must reside below
446   *                         the same backend base DN.
447   * @param  allowBind       Indicates whether users within the specified
448   *                         subtrees will be allowed to bind.
449   * @param  bypassUserDN    The DN of a user that will be allowed to perform
450   *                         write (add, delete, modify, and modify DN)
451   *                         operations in the specified subtrees.  It may be
452   *                         {@code null} if no bypass user is needed.
453   * @param  controls        The set of controls to include in the request.  It
454   *                         may be {@code null} or empty if no controls are
455   *                         needed.
456   *
457   * @return  The set subtree accessibility extended request that was created.
458   */
459  @NotNull()
460  public static SetSubtreeAccessibilityExtendedRequest
461              createSetReadOnlyRequest(
462                   @NotNull final Collection<String> subtreeBaseDNs,
463                   final boolean allowBind,
464                   @Nullable final String bypassUserDN,
465                   @Nullable final Control... controls)
466  {
467    Validator.ensureNotNull(subtreeBaseDNs);
468    Validator.ensureFalse(subtreeBaseDNs.isEmpty());
469
470    if (allowBind)
471    {
472      return new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
473           SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED, bypassUserDN,
474           controls);
475    }
476    else
477    {
478      return new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
479           SubtreeAccessibilityState.READ_ONLY_BIND_DENIED, bypassUserDN,
480           controls);
481    }
482  }
483
484
485
486  /**
487   * Creates a new set subtree accessibility extended request that will make the
488   * specified subtree hidden.
489   *
490   * @param  subtreeBaseDN  The base DN for the subtree to make hidden.  It must
491   *                        not be {@code null}.
492   * @param  bypassUserDN   The DN of a user that will be allowed to perform
493   *                        write (add, delete, modify, and modify DN)
494   *                        operations in the specified subtree.  It may be
495   *                        {@code null} if no bypass user is needed.
496   * @param  controls       The set of controls to include in the request.  It
497   *                        may be {@code null} or empty if no controls are
498   *                        needed.
499   *
500   * @return  The set subtree accessibility extended request that was created.
501   */
502  @NotNull()
503  public static SetSubtreeAccessibilityExtendedRequest
504              createSetHiddenRequest(@NotNull final String subtreeBaseDN,
505                                     @Nullable final String bypassUserDN,
506                                     @Nullable final Control... controls)
507  {
508    Validator.ensureNotNull(subtreeBaseDN);
509
510    return new SetSubtreeAccessibilityExtendedRequest(
511         Collections.singletonList(subtreeBaseDN),
512         SubtreeAccessibilityState.HIDDEN, bypassUserDN, controls);
513  }
514
515
516
517  /**
518   * Creates a new set subtree accessibility extended request that will make the
519   * specified subtrees hidden.
520   *
521   * @param  subtreeBaseDNs  The base DNs for the subtrees to make hidden.  It
522   *                         must not be {@code null} or empty.  If multiple
523   *                         base DNs are specified, then all must reside below
524   *                         the same backend base DN.
525   * @param  bypassUserDN    The DN of a user that will be allowed to perform
526   *                         write (add, delete, modify, and modify DN)
527   *                         operations in the specified subtrees.  It may be
528   *                         {@code null} if no bypass user is needed.
529   * @param  controls        The set of controls to include in the request.  It
530   *                         may be {@code null} or empty if no controls are
531   *                         needed.
532   *
533   * @return  The set subtree accessibility extended request that was created.
534   */
535  @NotNull()
536  public static SetSubtreeAccessibilityExtendedRequest
537              createSetHiddenRequest(
538                   @NotNull final Collection<String> subtreeBaseDNs,
539                   @Nullable final String bypassUserDN,
540                   @Nullable final Control... controls)
541  {
542    Validator.ensureNotNull(subtreeBaseDNs);
543    Validator.ensureFalse(subtreeBaseDNs.isEmpty());
544
545    return new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
546         SubtreeAccessibilityState.HIDDEN, bypassUserDN, controls);
547  }
548
549
550
551  /**
552   * Creates a new set subtree accessibility extended request that will place
553   * the specified subtree in a to-be-deleted state.  In this state, the
554   * subtree will exhibit the same characteristics as a hidden subtree, but with
555   * the added restriction that the accessibility state cannot be changed, and
556   * the restriction will only be removed when the base entry of the target
557   * subtree has been deleted.
558   *
559   * @param  subtreeBaseDN  The base DN for the subtree to mark as
560   *                        to-be-deleted.  It must not be {@code null}.
561   * @param  bypassUserDN   The DN of a user that will be allowed to perform
562   *                        write (add, delete, modify, and modify DN)
563   *                        operations in the specified subtree.  It must not be
564   *                        {@code null}.
565   * @param  controls       The set of controls to include in the request.  It
566   *                        may be {@code null} or empty if no controls are
567   *                        needed.
568   *
569   * @return  The set subtree accessibility extended request that was created.
570   */
571  @NotNull()
572  public static SetSubtreeAccessibilityExtendedRequest
573              createSetToBeDeletedRequest(@NotNull final String subtreeBaseDN,
574                                          @NotNull final String bypassUserDN,
575                                          @Nullable final Control... controls)
576  {
577    Validator.ensureNotNull(subtreeBaseDN);
578    Validator.ensureNotNull(bypassUserDN);
579
580    return new SetSubtreeAccessibilityExtendedRequest(
581         Collections.singletonList(subtreeBaseDN),
582         SubtreeAccessibilityState.TO_BE_DELETED, bypassUserDN, controls);
583  }
584
585
586
587  /**
588   * Creates a new set subtree accessibility extended request that will place
589   * the specified subtrees in a to-be-deleted state.  In this state, the
590   * subtrees will exhibit the same characteristics as hidden subtrees, but with
591   * the added restriction that the accessibility state cannot be changed, and
592   * the restriction will only be removed when the base entry of the target
593   * subtree has been deleted.
594   *
595   * @param  subtreeBaseDNs  The base DNs for the subtrees to make hidden.  It
596   *                         must not be {@code null} or empty.  If multiple
597   *                         base DNs are specified, then all must reside below
598   *                         the same backend base DN.
599   * @param  bypassUserDN    The DN of a user that will be allowed to perform
600   *                         write (add, delete, modify, and modify DN)
601   *                         operations in the specified subtrees.  It must not
602   *                         be {@code null}.
603   * @param  controls        The set of controls to include in the request.  It
604   *                         may be {@code null} or empty if no controls are
605   *                         needed.
606   *
607   * @return  The set subtree accessibility extended request that was created.
608   */
609  @NotNull()
610  public static SetSubtreeAccessibilityExtendedRequest
611              createSetToBeDeletedRequest(
612                   @NotNull final Collection<String> subtreeBaseDNs,
613                   @NotNull final String bypassUserDN,
614                   @Nullable final Control... controls)
615  {
616    Validator.ensureNotNull(subtreeBaseDNs);
617    Validator.ensureFalse(subtreeBaseDNs.isEmpty());
618
619    Validator.ensureNotNull(bypassUserDN);
620
621    return new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
622         SubtreeAccessibilityState.TO_BE_DELETED, bypassUserDN, controls);
623  }
624
625
626
627  /**
628   * Retrieves the base DN for the target subtree.  Note that if multiple
629   * base DNs are defined, this will only retrieve the first.  The
630   * {@link #getSubtreeBaseDNs()} method should be used to get the complete set
631   * of target subtree base DNs.
632   *
633   * @return  The base DN for the target subtree.
634   */
635  @NotNull()
636  public String getSubtreeBaseDN()
637  {
638    return subtreeBaseDNs.get(0);
639  }
640
641
642
643  /**
644   * Retrieves the base DNs for all target subtrees.
645   *
646   * @return  The base DNs for all target subtrees.
647   */
648  @NotNull()
649  public List<String> getSubtreeBaseDNs()
650  {
651    return subtreeBaseDNs;
652  }
653
654
655
656  /**
657   * Retrieves the accessibility state to apply to the target subtrees.
658   *
659   * @return  The accessibility state to apply to the target subtrees.
660   */
661  @NotNull()
662  public SubtreeAccessibilityState getAccessibilityState()
663  {
664    return accessibilityState;
665  }
666
667
668
669  /**
670   * Retrieves the DN of the user that will be allowed to bypass the
671   * restrictions imposed on the target subtrees for all other users.
672   *
673   * @return  The DN of the user that will be allowed to bypass the restrictions
674   *          imposed on the target subtrees for all other users, or
675   *          {@code null} if there are no restrictions to be imposed on the
676   *          target subtrees or if no bypass user is defined for those
677   *          subtrees.
678   */
679  @Nullable()
680  public String getBypassUserDN()
681  {
682    return bypassUserDN;
683  }
684
685
686
687  /**
688   * {@inheritDoc}
689   */
690  @Override()
691  @NotNull()
692  public SetSubtreeAccessibilityExtendedRequest duplicate()
693  {
694    return duplicate(getControls());
695  }
696
697
698
699  /**
700   * {@inheritDoc}
701   */
702  @Override()
703  @NotNull()
704  public SetSubtreeAccessibilityExtendedRequest duplicate(
705              @Nullable final Control[] controls)
706  {
707    final SetSubtreeAccessibilityExtendedRequest r =
708         new SetSubtreeAccessibilityExtendedRequest(subtreeBaseDNs,
709              accessibilityState, bypassUserDN, controls);
710    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
711    r.setIntermediateResponseListener(getIntermediateResponseListener());
712    r.setReferralDepth(getReferralDepth());
713    r.setReferralConnector(getReferralConnectorInternal());
714    return r;
715  }
716
717
718
719  /**
720   * {@inheritDoc}
721   */
722  @Override()
723  @NotNull()
724  public String getExtendedRequestName()
725  {
726    return INFO_EXTENDED_REQUEST_NAME_SET_SUBTREE_ACCESSIBILITY.get();
727  }
728
729
730
731  /**
732   * {@inheritDoc}
733   */
734  @Override()
735  public void toString(@NotNull final StringBuilder buffer)
736  {
737    buffer.append("SetSubtreeAccessibilityExtendedRequest(baseDNs={");
738
739    final Iterator<String> dnIterator = subtreeBaseDNs.iterator();
740    while (dnIterator.hasNext())
741    {
742      buffer.append('"');
743      buffer.append(dnIterator.next());
744      buffer.append('"');
745
746      if (dnIterator.hasNext())
747      {
748        buffer.append(", ");
749      }
750    }
751
752    buffer.append("}, accessibilityType=\"");
753    buffer.append(accessibilityState.getStateName());
754    buffer.append('"');
755
756    if (bypassUserDN != null)
757    {
758      buffer.append(", bypassUserDN=\"");
759      buffer.append(bypassUserDN);
760      buffer.append('"');
761    }
762
763    final Control[] controls = getControls();
764    if (controls.length > 0)
765    {
766      buffer.append(", controls={");
767      for (int i=0; i < controls.length; i++)
768      {
769        if (i > 0)
770        {
771          buffer.append(", ");
772        }
773
774        buffer.append(controls[i]);
775      }
776      buffer.append('}');
777    }
778
779    buffer.append(')');
780  }
781}