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.util.List;
041
042import com.unboundid.util.NotExtensible;
043import com.unboundid.util.NotNull;
044import com.unboundid.util.Nullable;
045import com.unboundid.util.ThreadSafety;
046import com.unboundid.util.ThreadSafetyLevel;
047import com.unboundid.util.Validator;
048
049
050
051/**
052 * This class is the superclass of all types of LDAP requests that can be
053 * altered.  It provides methods for updating the set of controls to include as
054 * part of the request and for configuring a response timeout, which is
055 * the maximum length of time that the SDK should wait for a response to the
056 * request before returning an error back to the caller.
057 */
058@NotExtensible()
059@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
060public abstract class UpdatableLDAPRequest
061       extends LDAPRequest
062{
063  /**
064   * The serial version UID for this serializable class.
065   */
066  private static final long serialVersionUID = 2487230102594573848L;
067
068
069
070  /**
071   * Creates a new LDAP request with the provided set of controls.
072   *
073   * @param  controls  The set of controls to include in this LDAP request.
074   */
075  protected UpdatableLDAPRequest(@Nullable final Control[] controls)
076  {
077    super(controls);
078  }
079
080
081
082  /**
083   * Specifies the set of controls for this request.
084   *
085   * @param  controls  The set of controls for this request.
086   */
087  public final void setControls(@Nullable final Control... controls)
088  {
089    if (controls == null)
090    {
091      setControlsInternal(NO_CONTROLS);
092    }
093    else
094    {
095      setControlsInternal(controls);
096    }
097  }
098
099
100
101  /**
102   * Specifies the set of controls for this request.
103   *
104   * @param  controls  The set of controls for this request.
105   */
106  public final void setControls(@Nullable final List<Control> controls)
107  {
108    if ((controls == null) || controls.isEmpty())
109    {
110      setControlsInternal(NO_CONTROLS);
111    }
112    else
113    {
114      final Control[] controlArray = new Control[controls.size()];
115      setControlsInternal(controls.toArray(controlArray));
116    }
117  }
118
119
120
121  /**
122   * Removes all controls from this request.
123   */
124  public final void clearControls()
125  {
126    setControlsInternal(NO_CONTROLS);
127  }
128
129
130
131  /**
132   * Adds the provided control to the set of controls for this request.
133   *
134   * @param  control  The control to add to the set of controls for this
135   *                  request.  It must not be {@code null}.
136   */
137  public final void addControl(@NotNull final Control control)
138  {
139    Validator.ensureNotNull(control);
140
141    final Control[] controls = getControls();
142
143    final Control[] newControls = new Control[controls.length+1];
144    System.arraycopy(controls, 0, newControls, 0, controls.length);
145    newControls[controls.length] = control;
146
147    setControlsInternal(newControls);
148  }
149
150
151
152  /**
153   * Adds the provided controls to the set of controls for this request.
154   *
155   * @param  controls  The controls to add to the set of controls for this
156   *                   request.
157   */
158  public final void addControls(@Nullable final Control... controls)
159  {
160    if ((controls == null) || (controls.length == 0))
161    {
162      return;
163    }
164
165    final Control[] currentControls = getControls();
166
167    final Control[] newControls =
168         new Control[currentControls.length + controls.length];
169    System.arraycopy(currentControls, 0, newControls, 0,
170                     currentControls.length);
171    System.arraycopy(controls, 0, newControls, currentControls.length,
172                     controls.length);
173
174    setControlsInternal(newControls);
175  }
176
177
178
179  /**
180   * Removes the control with the specified OID from the set of controls for
181   * this request.  If this request has multiple controls with the same OID,
182   * then only the first will be removed.
183   *
184   * @param  oid  The OID of the control to remove.  It must not be
185   *              {@code null}.
186   *
187   * @return  The control that was removed, or {@code null} if this request does
188   *          not have any control with the specified OID.
189   */
190  @Nullable()
191  public final Control removeControl(@NotNull final String oid)
192  {
193    Validator.ensureNotNull(oid);
194
195    final Control[] controls = getControls();
196
197    int pos = -1;
198    Control c = null;
199    for (int i=0; i < controls.length; i++)
200    {
201      if (controls[i].getOID().equals(oid))
202      {
203        c = controls[i];
204        pos = i;
205        break;
206      }
207    }
208
209    if (pos < 0)
210    {
211      return null;
212    }
213
214    if (controls.length == 1)
215    {
216      setControlsInternal(NO_CONTROLS);
217    }
218    else
219    {
220      final Control[] newControls = new Control[controls.length - 1];
221      for (int i=0,j=0; i < controls.length; i++)
222      {
223        if (i != pos)
224        {
225          newControls[j++] = controls[i];
226        }
227      }
228      setControlsInternal(newControls);
229    }
230
231    return c;
232  }
233
234
235
236  /**
237   * Removes the provided control from the set of controls for this request.
238   * This will have no impact if the provided control is not included in the set
239   * of controls for this request.
240   *
241   * @param  control  The control to remove from the set of controls for this
242   *                  request.  It must not be {@code null}.
243   *
244   * @return  {@code true} if the control was found and removed, or
245   *          {@code false} if not.
246   */
247  public final boolean removeControl(@NotNull final Control control)
248  {
249    Validator.ensureNotNull(control);
250
251    final Control[] controls = getControls();
252
253    int pos = -1;
254    for (int i=0; i < controls.length; i++)
255    {
256      if (controls[i].equals(control))
257      {
258        pos = i;
259        break;
260      }
261    }
262
263    if (pos < 0)
264    {
265      return false;
266    }
267
268    if (controls.length == 1)
269    {
270      setControlsInternal(NO_CONTROLS);
271    }
272    else
273    {
274      final Control[] newControls = new Control[controls.length - 1];
275      for (int i=0,j=0; i < controls.length; i++)
276      {
277        if (i != pos)
278        {
279          newControls[j++] = controls[i];
280        }
281      }
282      setControlsInternal(newControls);
283    }
284
285    return true;
286  }
287
288
289
290  /**
291   * Replaces the control with the same OID as the provided control with the
292   * provided control.  If no control with the same OID exists in the request,
293   * then the control will be added to the request.  If the request has multiple
294   * controls with the same OID as the new control, then only the first will be
295   * replaced.
296   *
297   * @param  control  The control to use in place of the existing control with
298   *                  the same OID.  It must not be {@code null}.
299   *
300   * @return  The control that was replaced, or {@code null} if there was no
301   *          control with the same OID as the provided control.
302   */
303  @Nullable()
304  public final Control replaceControl(@NotNull final Control control)
305  {
306    Validator.ensureNotNull(control);
307
308    return replaceControl(control.getOID(), control);
309  }
310
311
312
313  /**
314   * Replaces the control with the specified OID with the provided control. If
315   * no control with the given OID exists in the request, then a new control
316   * will be added.  If this request has multiple controls with the specified
317   * OID, then only the first will be replaced.
318   *
319   * @param  oid      The OID of the control to replace with the provided
320   *                  control.  It must not be {@code null}.
321   * @param  control  The control to use in place of the control with the
322   *                  specified OID.  It may be {@code null} if the control
323   *                  should be removed.  It may have a different OID than the
324   *                  OID of the control being replaced.
325   *
326   * @return  The control that was replaced, or {@code null} if there was no
327   *          control with the specified OID.
328   */
329  @Nullable()
330  public final Control replaceControl(@NotNull final String oid,
331                                      @Nullable final Control control)
332  {
333    Validator.ensureNotNull(oid);
334
335    if (control == null)
336    {
337      return removeControl(oid);
338    }
339
340    final Control[] controls = getControls();
341    for (int i=0; i < controls.length; i++)
342    {
343      if (controls[i].getOID().equals(oid))
344      {
345        final Control c = controls[i];
346        controls[i] = control;
347        setControlsInternal(controls);
348        return c;
349      }
350    }
351
352    final Control[] newControls = new Control[controls.length+1];
353    System.arraycopy(controls, 0, newControls, 0, controls.length);
354    newControls[controls.length] = control;
355    setControlsInternal(newControls);
356    return null;
357  }
358}