001    /*
002     * Copyright 2007-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 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     */
021    package com.unboundid.ldap.sdk;
022    
023    
024    
025    import java.util.List;
026    
027    import com.unboundid.util.NotExtensible;
028    import com.unboundid.util.ThreadSafety;
029    import com.unboundid.util.ThreadSafetyLevel;
030    
031    import 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)
044    public 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    }