001/*
002 * Copyright 2007-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2018 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk;
022
023
024
025import java.util.List;
026
027import com.unboundid.util.NotExtensible;
028import com.unboundid.util.ThreadSafety;
029import com.unboundid.util.ThreadSafetyLevel;
030import com.unboundid.util.Validator;
031
032
033
034/**
035 * This class is the superclass of all types of LDAP requests that can be
036 * altered.  It provides methods for updating the set of controls to include as
037 * part of the request and for configuring a response timeout, which is
038 * the maximum length of time that the SDK should wait for a response to the
039 * request before returning an error back to the caller.
040 */
041@NotExtensible()
042@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
043public abstract class UpdatableLDAPRequest
044       extends LDAPRequest
045{
046  /**
047   * The serial version UID for this serializable class.
048   */
049  private static final long serialVersionUID = 2487230102594573848L;
050
051
052
053  /**
054   * Creates a new LDAP request with the provided set of controls.
055   *
056   * @param  controls  The set of controls to include in this LDAP request.
057   */
058  protected UpdatableLDAPRequest(final Control[] controls)
059  {
060    super(controls);
061  }
062
063
064
065  /**
066   * Specifies the set of controls for this request.
067   *
068   * @param  controls  The set of controls for this request.
069   */
070  public final void setControls(final Control... controls)
071  {
072    if (controls == null)
073    {
074      setControlsInternal(NO_CONTROLS);
075    }
076    else
077    {
078      setControlsInternal(controls);
079    }
080  }
081
082
083
084  /**
085   * Specifies the set of controls for this request.
086   *
087   * @param  controls  The set of controls for this request.
088   */
089  public final void setControls(final List<Control> controls)
090  {
091    if ((controls == null) || controls.isEmpty())
092    {
093      setControlsInternal(NO_CONTROLS);
094    }
095    else
096    {
097      final Control[] controlArray = new Control[controls.size()];
098      setControlsInternal(controls.toArray(controlArray));
099    }
100  }
101
102
103
104  /**
105   * Removes all controls from this request.
106   */
107  public final void clearControls()
108  {
109    setControlsInternal(NO_CONTROLS);
110  }
111
112
113
114  /**
115   * Adds the provided control to the set of controls for this request.
116   *
117   * @param  control  The control to add to the set of controls for this
118   *                  request.  It must not be {@code null}.
119   */
120  public final void addControl(final Control control)
121  {
122    Validator.ensureNotNull(control);
123
124    final Control[] controls = getControls();
125
126    final Control[] newControls = new Control[controls.length+1];
127    System.arraycopy(controls, 0, newControls, 0, controls.length);
128    newControls[controls.length] = control;
129
130    setControlsInternal(newControls);
131  }
132
133
134
135  /**
136   * Adds the provided controls to the set of controls for this request.
137   *
138   * @param  controls  The controls to add to the set of controls for this
139   *                   request.
140   */
141  public final void addControls(final Control... controls)
142  {
143    if ((controls == null) || (controls.length == 0))
144    {
145      return;
146    }
147
148    final Control[] currentControls = getControls();
149
150    final Control[] newControls =
151         new Control[currentControls.length + controls.length];
152    System.arraycopy(currentControls, 0, newControls, 0,
153                     currentControls.length);
154    System.arraycopy(controls, 0, newControls, currentControls.length,
155                     controls.length);
156
157    setControlsInternal(newControls);
158  }
159
160
161
162  /**
163   * Removes the control with the specified OID from the set of controls for
164   * this request.  If this request has multiple controls with the same OID,
165   * then only the first will be removed.
166   *
167   * @param  oid  The OID of the control to remove.  It must not be
168   *              {@code null}.
169   *
170   * @return  The control that was removed, or {@code null} if this request does
171   *          not have any control with the specified OID.
172   */
173  public final Control removeControl(final String oid)
174  {
175    Validator.ensureNotNull(oid);
176
177    final Control[] controls = getControls();
178
179    int pos = -1;
180    Control c = null;
181    for (int i=0; i < controls.length; i++)
182    {
183      if (controls[i].getOID().equals(oid))
184      {
185        c = controls[i];
186        pos = i;
187        break;
188      }
189    }
190
191    if (pos < 0)
192    {
193      return null;
194    }
195
196    if (controls.length == 1)
197    {
198      setControlsInternal(NO_CONTROLS);
199    }
200    else
201    {
202      final Control[] newControls = new Control[controls.length - 1];
203      for (int i=0,j=0; i < controls.length; i++)
204      {
205        if (i != pos)
206        {
207          newControls[j++] = controls[i];
208        }
209      }
210      setControlsInternal(newControls);
211    }
212
213    return c;
214  }
215
216
217
218  /**
219   * Removes the provided control from the set of controls for this request.
220   * This will have no impact if the provided control is not included in the set
221   * of controls for this request.
222   *
223   * @param  control  The control to remove from the set of controls for this
224   *                  request.  It must not be {@code null}.
225   *
226   * @return  {@code true} if the control was found and removed, or
227   *          {@code false} if not.
228   */
229  public final boolean removeControl(final Control control)
230  {
231    Validator.ensureNotNull(control);
232
233    final Control[] controls = getControls();
234
235    int pos = -1;
236    for (int i=0; i < controls.length; i++)
237    {
238      if (controls[i].equals(control))
239      {
240        pos = i;
241        break;
242      }
243    }
244
245    if (pos < 0)
246    {
247      return false;
248    }
249
250    if (controls.length == 1)
251    {
252      setControlsInternal(NO_CONTROLS);
253    }
254    else
255    {
256      final Control[] newControls = new Control[controls.length - 1];
257      for (int i=0,j=0; i < controls.length; i++)
258      {
259        if (i != pos)
260        {
261          newControls[j++] = controls[i];
262        }
263      }
264      setControlsInternal(newControls);
265    }
266
267    return true;
268  }
269
270
271
272  /**
273   * Replaces the control with the same OID as the provided control with the
274   * provided control.  If no control with the same OID exists in the request,
275   * then the control will be added to the request.  If the request has multiple
276   * controls with the same OID as the new control, then only the first will be
277   * replaced.
278   *
279   * @param  control  The control to use in place of the existing control with
280   *                  the same OID.  It must not be {@code null}.
281   *
282   * @return  The control that was replaced, or {@code null} if there was no
283   *          control with the same OID as the provided control.
284   */
285  public final Control replaceControl(final Control control)
286  {
287    Validator.ensureNotNull(control);
288
289    return replaceControl(control.getOID(), control);
290  }
291
292
293
294  /**
295   * Replaces the control with the specified OID with the provided control. If
296   * no control with the given OID exists in the request, then a new control
297   * will be added.  If this request has multiple controls with the specified
298   * OID, then only the first will be replaced.
299   *
300   * @param  oid      The OID of the control to replace with the provided
301   *                  control.  It must not be {@code null}.
302   * @param  control  The control to use in place of the control with the
303   *                  specified OID.  It may be {@code null} if the control
304   *                  should be removed.  It may have a different OID than the
305   *                  OID of the control being replaced.
306   *
307   * @return  The control that was replaced, or {@code null} if there was no
308   *          control with the specified OID.
309   */
310  public final Control replaceControl(final String oid, final Control control)
311  {
312    Validator.ensureNotNull(oid);
313
314    if (control == null)
315    {
316      return removeControl(oid);
317    }
318
319    final Control[] controls = getControls();
320    for (int i=0; i < controls.length; i++)
321    {
322      if (controls[i].getOID().equals(oid))
323      {
324        final Control c = controls[i];
325        controls[i] = control;
326        setControlsInternal(controls);
327        return c;
328      }
329    }
330
331    final Control[] newControls = new Control[controls.length+1];
332    System.arraycopy(controls, 0, newControls, 0, controls.length);
333    newControls[controls.length] = control;
334    setControlsInternal(newControls);
335    return null;
336  }
337}