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