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