001/*
002 * Copyright 2009-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-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 */
021package com.unboundid.ldap.sdk.migrate.ldapjdk;
022
023
024
025import com.unboundid.asn1.ASN1OctetString;
026import com.unboundid.ldap.sdk.AddRequest;
027import com.unboundid.ldap.sdk.BindResult;
028import com.unboundid.ldap.sdk.CompareRequest;
029import com.unboundid.ldap.sdk.CompareResult;
030import com.unboundid.ldap.sdk.Control;
031import com.unboundid.ldap.sdk.DeleteRequest;
032import com.unboundid.ldap.sdk.DereferencePolicy;
033import com.unboundid.ldap.sdk.ExtendedRequest;
034import com.unboundid.ldap.sdk.ExtendedResult;
035import com.unboundid.ldap.sdk.Filter;
036import com.unboundid.ldap.sdk.InternalSDKHelper;
037import com.unboundid.ldap.sdk.LDAPConnectionOptions;
038import com.unboundid.ldap.sdk.LDAPResult;
039import com.unboundid.ldap.sdk.Modification;
040import com.unboundid.ldap.sdk.ModifyDNRequest;
041import com.unboundid.ldap.sdk.ModifyRequest;
042import com.unboundid.ldap.sdk.ResultCode;
043import com.unboundid.ldap.sdk.SearchRequest;
044import com.unboundid.ldap.sdk.SearchResult;
045import com.unboundid.ldap.sdk.SearchScope;
046import com.unboundid.ldap.sdk.SimpleBindRequest;
047import com.unboundid.ldap.sdk.UpdatableLDAPRequest;
048import com.unboundid.util.Mutable;
049import com.unboundid.util.NotExtensible;
050import com.unboundid.util.ThreadSafety;
051import com.unboundid.util.ThreadSafetyLevel;
052
053import static com.unboundid.util.Debug.*;
054
055
056
057/**
058 * This class provides an object that may be used to communicate with an LDAP
059 * directory server.
060 * <BR><BR>
061 * This class is primarily intended to be used in the process of updating
062 * applications which use the Netscape Directory SDK for Java to switch to or
063 * coexist with the UnboundID LDAP SDK for Java.  For applications not written
064 * using the Netscape Directory SDK for Java, the
065 * {@link com.unboundid.ldap.sdk.LDAPConnection} class should be used instead.
066 */
067@Mutable()
068@NotExtensible()
069@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
070public class LDAPConnection
071{
072  /**
073   * The integer value for the DEREF_NEVER dereference policy.
074   */
075  public static final int DEREF_NEVER = DereferencePolicy.NEVER.intValue();
076
077
078
079  /**
080   * The integer value for the DEREF_SEARCHING dereference policy.
081   */
082  public static final int DEREF_SEARCHING =
083       DereferencePolicy.SEARCHING.intValue();
084
085
086
087  /**
088   * The integer value for the DEREF_FINDING dereference policy.
089   */
090  public static final int DEREF_FINDING =
091       DereferencePolicy.FINDING.intValue();
092
093
094
095  /**
096   * The integer value for the DEREF_ALWAYS dereference policy.
097   */
098  public static final int DEREF_ALWAYS =
099       DereferencePolicy.ALWAYS.intValue();
100
101
102
103  /**
104   * The integer value for the SCOPE_BASE search scope.
105   */
106  public static final int SCOPE_BASE = SearchScope.BASE_INT_VALUE;
107
108
109
110  /**
111   * The integer value for the SCOPE_ONE search scope.
112   */
113  public static final int SCOPE_ONE = SearchScope.ONE_INT_VALUE;
114
115
116
117  /**
118   * The integer value for the SCOPE_SUB search scope.
119   */
120  public static final int SCOPE_SUB = SearchScope.SUB_INT_VALUE;
121
122
123
124  // The connection used to perform the actual communication with the server.
125  private volatile com.unboundid.ldap.sdk.LDAPConnection conn;
126
127  // The default constraints that will be used for non-search operations.
128  private LDAPConstraints constraints;
129
130  // The set of controls returned from the last operation.
131  private LDAPControl[] responseControls;
132
133  // The default constraints that will be used for search operations.
134  private LDAPSearchConstraints searchConstraints;
135
136  // The socket factory for this connection.
137  private LDAPSocketFactory socketFactory;
138
139  // The DN last used to bind to the server.
140  private String authDN;
141
142  // The password last used to bind to the server.
143  private String authPW;
144
145
146
147  /**
148   * Creates a new LDAP connection which will use the default socket factory.
149   */
150  public LDAPConnection()
151  {
152    this(null);
153  }
154
155
156
157  /**
158   * Creates a new LDAP connection which will use the provided socket factory.
159   *
160   * @param  socketFactory  The socket factory to use when creating the socket
161   *                        to use for communicating with the server.
162   */
163  public LDAPConnection(final LDAPSocketFactory socketFactory)
164  {
165    this.socketFactory = socketFactory;
166    if (socketFactory == null)
167    {
168      conn = new com.unboundid.ldap.sdk.LDAPConnection();
169    }
170    else
171    {
172
173      conn = new com.unboundid.ldap.sdk.LDAPConnection(
174           new LDAPToJavaSocketFactory(socketFactory));
175    }
176
177    authDN = null;
178    authPW = null;
179
180    constraints       = new LDAPConstraints();
181    searchConstraints = new LDAPSearchConstraints();
182  }
183
184
185
186  /**
187   * Closes the connection to the server if the client forgets to do so.
188   *
189   * @throws  Throwable  If a problem occurs.
190   */
191  @Override()
192  protected void finalize()
193            throws Throwable
194  {
195    conn.close();
196
197    super.finalize();
198  }
199
200
201
202  /**
203   * Retrieves the {@link com.unboundid.ldap.sdk.LDAPConnection} object used to
204   * back this connection.
205   *
206   * @return  The {@code com.unboundid.ldap.sdk.LDAPConnection} object used to
207   *          back this connection.
208   */
209  public com.unboundid.ldap.sdk.LDAPConnection getSDKConnection()
210  {
211    return conn;
212  }
213
214
215
216  /**
217   * Retrieves the address to which the connection is established.
218   *
219   * @return  The address to which the connection is established.
220   */
221  public String getHost()
222  {
223    return conn.getConnectedAddress();
224  }
225
226
227
228  /**
229   * Retrieves the port to which the connection is established.
230   *
231   * @return  The port to which the connection is established.
232   */
233  public int getPort()
234  {
235    return conn.getConnectedPort();
236  }
237
238
239
240  /**
241   * Retrieves the DN of the user that last authenticated on this connection.
242   *
243   * @return  The DN of the user that last authenticated on this connection,
244   *          or {@code null} if it is not available.
245   */
246  public String getAuthenticationDN()
247  {
248    return authDN;
249  }
250
251
252
253  /**
254   * Retrieves the password of the user that last authenticated on this
255   * connection.
256   *
257   * @return  The password of the user that last authenticated on this
258   *           connection, or {@code null} if it is not available.
259   */
260  public String getAuthenticationPassword()
261  {
262    return authPW;
263  }
264
265
266
267  /**
268   * Retrieves the maximum length of time to wait for the connection to be
269   * established, in seconds.
270   *
271   * @return  The maximum length of time to wait for the connection to be
272   *          established.
273   */
274  public int getConnectTimeout()
275  {
276    final int connectTimeoutMillis =
277         conn.getConnectionOptions().getConnectTimeoutMillis();
278    if (connectTimeoutMillis > 0)
279    {
280      return Math.max(1, (connectTimeoutMillis / 1000));
281    }
282    else
283    {
284      return 0;
285    }
286  }
287
288
289
290  /**
291   * Specifies the maximum length of time to wait for the connection to be
292   * established, in seconds.
293   *
294   * @param  timeout  The maximum length of time to wait for the connection to
295   *                  be established.
296   */
297  public void setConnectTimeout(final int timeout)
298  {
299    final LDAPConnectionOptions options = conn.getConnectionOptions();
300
301    if (timeout > 0)
302    {
303      options.setConnectTimeoutMillis(1000 * timeout);
304    }
305    else
306    {
307      options.setConnectTimeoutMillis(0);
308    }
309
310    conn.setConnectionOptions(options);
311  }
312
313
314
315  /**
316   * Retrieves the socket factory for this LDAP connection, if specified.
317   *
318   * @return  The socket factory for this LDAP connection, or {@code null} if
319   *          none has been provided.
320   */
321  public LDAPSocketFactory getSocketFactory()
322  {
323    return socketFactory;
324  }
325
326
327
328  /**
329   * Sets the socket factory for this LDAP connection.
330   *
331   * @param  socketFactory  The socket factory for this LDAP connection.
332   */
333  public void setSocketFactory(final LDAPSocketFactory socketFactory)
334  {
335    this.socketFactory = socketFactory;
336
337    if (socketFactory == null)
338    {
339      conn.setSocketFactory(null);
340    }
341    else
342    {
343      conn.setSocketFactory(new LDAPToJavaSocketFactory(socketFactory));
344    }
345  }
346
347
348
349  /**
350   * Retrieves the constraints for this connection.
351   *
352   * @return  The constraints for this connection.
353   */
354  public LDAPConstraints getConstraints()
355  {
356    return constraints;
357  }
358
359
360
361  /**
362   * Updates the constraints for this connection.
363   *
364   * @param  constraints  The constraints for this connection.
365   */
366  public void setConstraints(final LDAPConstraints constraints)
367  {
368    if (constraints == null)
369    {
370      this.constraints = new LDAPConstraints();
371    }
372    else
373    {
374      this.constraints = constraints;
375    }
376  }
377
378
379
380  /**
381   * Retrieves the search constraints for this connection.
382   *
383   * @return  The search constraints for this connection.
384   */
385  public LDAPSearchConstraints getSearchConstraints()
386  {
387    return searchConstraints;
388  }
389
390
391
392  /**
393   * Updates the search constraints for this connection.
394   *
395   * @param  searchConstraints  The search constraints for this connection.
396   */
397  public void setSearchConstraints(
398                   final LDAPSearchConstraints searchConstraints)
399  {
400    if (searchConstraints == null)
401    {
402      this.searchConstraints = new LDAPSearchConstraints();
403    }
404    else
405    {
406      this.searchConstraints = searchConstraints;
407    }
408  }
409
410
411
412  /**
413   * Retrieves the response controls from the last operation processed on this
414   * connection.
415   *
416   * @return  The response controls from the last operation processed on this
417   *          connection, or {@code null} if there were none.
418   */
419  public LDAPControl[] getResponseControls()
420  {
421    return responseControls;
422  }
423
424
425
426  /**
427   * Indicates whether this connection is currently established.
428   *
429   * @return  {@code true} if this connection is currently established, or
430   *          {@code false} if not.
431   */
432  public boolean isConnected()
433  {
434    return conn.isConnected();
435  }
436
437
438
439  /**
440   * Attempts to establish this connection with the provided information.
441   *
442   * @param  host  The address of the server to which the connection should be
443   *               established.
444   * @param  port  The port of the server to which the connection should be
445   *               established.
446   *
447   * @throws  LDAPException  If a problem occurs while attempting to establish
448   *                         this connection.
449   */
450  public void connect(final String host, final int port)
451         throws LDAPException
452  {
453    authDN           = null;
454    authPW           = null;
455    responseControls = null;
456
457    try
458    {
459      conn.close();
460      if (socketFactory == null)
461      {
462        conn = new com.unboundid.ldap.sdk.LDAPConnection(host, port);
463      }
464      else
465      {
466
467        conn = new com.unboundid.ldap.sdk.LDAPConnection(
468             new LDAPToJavaSocketFactory(socketFactory), host, port);
469      }
470    }
471    catch (final com.unboundid.ldap.sdk.LDAPException le)
472    {
473      debugException(le);
474      throw new LDAPException(le);
475    }
476  }
477
478
479
480  /**
481   * Attempts to establish and authenticate this connection with the provided
482   * information.
483   *
484   * @param  host      The address of the server to which the connection should
485   *                   be established.
486   * @param  port      The port of the server to which the connection should be
487   *                   established.
488   * @param  dn        The DN to use to bind to the server.
489   * @param  password  The password to use to bind to the server.
490   *
491   * @throws  LDAPException  If a problem occurs while attempting to establish
492   *                         or authenticate this connection.  If an exception
493   *                         is thrown, then the connection will not be
494   *                         established.
495   */
496  public void connect(final String host, final int port, final String dn,
497                      final String password)
498         throws LDAPException
499  {
500    connect(3, host, port, dn, password, null);
501  }
502
503
504
505  /**
506   * Attempts to establish and authenticate this connection with the provided
507   * information.
508   *
509   * @param  host         The address of the server to which the connection
510   *                      should be established.
511   * @param  port         The port of the server to which the connection should
512   *                      be established.
513   * @param  dn           The DN to use to bind to the server.
514   * @param  password     The password to use to bind to the server.
515   * @param  constraints  The constraints to use when processing the bind.
516   *
517   * @throws  LDAPException  If a problem occurs while attempting to establish
518   *                         or authenticate this connection.  If an exception
519   *                         is thrown, then the connection will not be
520   *                         established.
521   */
522  public void connect(final String host, final int port, final String dn,
523                      final String password, final LDAPConstraints constraints)
524         throws LDAPException
525  {
526    connect(3, host, port, dn, password, constraints);
527  }
528
529
530
531  /**
532   * Attempts to establish and authenticate this connection with the provided
533   * information.
534   *
535   * @param  version   The LDAP protocol version to use for the connection.
536   *                   This will be ignored, since this implementation only
537   *                   supports LDAPv3.
538   * @param  host      The address of the server to which the connection should
539   *                   be established.
540   * @param  port      The port of the server to which the connection should be
541   *                   established.
542   * @param  dn        The DN to use to bind to the server.
543   * @param  password  The password to use to bind to the server.
544   *
545   * @throws  LDAPException  If a problem occurs while attempting to establish
546   *                         or authenticate this connection.  If an exception
547   *                         is thrown, then the connection will not be
548   *                         established.
549   */
550  public void connect(final int version, final String host, final int port,
551                      final String dn, final String password)
552         throws LDAPException
553  {
554    connect(version, host, port, dn, password, null);
555  }
556
557
558
559  /**
560   * Attempts to establish and authenticate this connection with the provided
561   * information.
562   *
563   * @param  version      The LDAP protocol version to use for the connection.
564   *                      This will be ignored, since this implementation only
565   *                      supports LDAPv3.
566   * @param  host         The address of the server to which the connection
567   *                      should be established.
568   * @param  port         The port of the server to which the connection should
569   *                      be established.
570   * @param  dn           The DN to use to bind to the server.
571   * @param  password     The password to use to bind to the server.
572   * @param  constraints  The constraints to use when processing the bind.
573   *
574   * @throws  LDAPException  If a problem occurs while attempting to establish
575   *                         or authenticate this connection.  If an exception
576   *                         is thrown, then the connection will not be
577   *                         established.
578   */
579  public void connect(final int version, final String host, final int port,
580                      final String dn, final String password,
581                      final LDAPConstraints constraints)
582         throws LDAPException
583  {
584    connect(host, port);
585
586    try
587    {
588      if ((dn != null) && (password != null))
589      {
590        bind(version, dn, password, constraints);
591      }
592    }
593    catch (LDAPException le)
594    {
595      conn.close();
596      throw le;
597    }
598  }
599
600
601
602  /**
603   * Unbinds and disconnects from the directory server.
604   *
605   * @throws  LDAPException  If a problem occurs.
606   */
607  public void disconnect()
608         throws LDAPException
609  {
610    authDN = null;
611    authPW = null;
612
613    conn.close();
614    if (socketFactory == null)
615    {
616      conn = new com.unboundid.ldap.sdk.LDAPConnection();
617    }
618    else
619    {
620
621      conn = new com.unboundid.ldap.sdk.LDAPConnection(
622           new LDAPToJavaSocketFactory(socketFactory));
623    }
624  }
625
626
627
628  /**
629   * Disconnects from the directory server and attempts to re-connect and
630   * re-authenticate.
631   *
632   * @throws  LDAPException  If a problem occurs.  If an exception is thrown,
633   *                         the connection will have been closed.
634   */
635  public void reconnect()
636         throws LDAPException
637  {
638    final String host = getHost();
639    final int    port = getPort();
640    final String dn   = authDN;
641    final String pw   = authPW;
642
643    if ((dn == null) || (pw == null))
644    {
645      connect(host, port);
646    }
647    else
648    {
649      connect(host, port, dn, pw);
650    }
651  }
652
653
654
655  /**
656   * Sends a request to abandon the request with the specified message ID.
657   *
658   * @param  id  The message ID of the operation to abandon.
659   *
660   * @throws  LDAPException  If a problem occurs while sending the request.
661   */
662  public void abandon(final int id)
663         throws LDAPException
664  {
665    try
666    {
667      conn.abandon(InternalSDKHelper.createAsyncRequestID(id, conn),
668                   getControls(null));
669    }
670    catch (com.unboundid.ldap.sdk.LDAPException le)
671    {
672      debugException(le);
673      throw new LDAPException(le);
674    }
675  }
676
677
678
679  /**
680   * Adds the provided entry to the directory.
681   *
682   * @param  entry  The entry to be added.
683   *
684   * @throws  LDAPException  If a problem occurs while adding the entry.
685   */
686  public void add(final LDAPEntry entry)
687         throws LDAPException
688  {
689    add(entry, null);
690  }
691
692
693
694  /**
695   * Adds the provided entry to the directory.
696   *
697   * @param  entry        The entry to be added.
698   * @param  constraints  The constraints to use for the add operation.
699   *
700   * @throws  LDAPException  If a problem occurs while adding the entry.
701   */
702  public void add(final LDAPEntry entry, final LDAPConstraints constraints)
703         throws LDAPException
704  {
705    final AddRequest addRequest = new AddRequest(entry.toEntry());
706    update(addRequest, constraints);
707
708    try
709    {
710      final LDAPResult result = conn.add(addRequest);
711      setResponseControls(result);
712    }
713    catch (com.unboundid.ldap.sdk.LDAPException le)
714    {
715      debugException(le);
716      setResponseControls(le);
717      throw new LDAPException(le);
718    }
719  }
720
721
722
723
724  /**
725   * Authenticates to the directory server using a simple bind with the provided
726   * information.
727   *
728   * @param  dn        The DN of the user for the bind.
729   * @param  password  The password to use for the bind.
730   *
731   * @throws  LDAPException  If the bind attempt fails.
732   */
733  public void authenticate(final String dn, final String password)
734         throws LDAPException
735  {
736    bind(3, dn, password, null);
737  }
738
739
740
741  /**
742   * Authenticates to the directory server using a simple bind with the provided
743   * information.
744   *
745   * @param  dn           The DN of the user for the bind.
746   * @param  password     The password to use for the bind.
747   * @param  constraints  The constraints to use for the bind operation.
748   *
749   * @throws  LDAPException  If the bind attempt fails.
750   */
751  public void authenticate(final String dn, final String password,
752                           final LDAPConstraints constraints)
753         throws LDAPException
754  {
755    bind(3, dn, password, constraints);
756  }
757
758
759
760  /**
761   * Authenticates to the directory server using a simple bind with the provided
762   * information.
763   *
764   * @param  version   The LDAP protocol version to use.  This will be ignored,
765   *                   since this implementation only supports LDAPv3.
766   * @param  dn        The DN of the user for the bind.
767   * @param  password  The password to use for the bind.
768   *
769   * @throws  LDAPException  If the bind attempt fails.
770   */
771  public void authenticate(final int version, final String dn,
772                           final String password)
773         throws LDAPException
774  {
775    bind(version, dn, password, null);
776  }
777
778
779
780  /**
781   * Authenticates to the directory server using a simple bind with the provided
782   * information.
783   *
784   * @param  version      The LDAP protocol version to use.  This will be
785   *                      ignored, since this implementation only supports
786   *                      LDAPv3.
787   * @param  dn           The DN of the user for the bind.
788   * @param  password     The password to use for the bind.
789   * @param  constraints  The constraints to use for the bind operation.
790   *
791   * @throws  LDAPException  If the bind attempt fails.
792   */
793  public void authenticate(final int version, final String dn,
794                           final String password,
795                           final LDAPConstraints constraints)
796         throws LDAPException
797  {
798    bind(version, dn, password, constraints);
799  }
800
801
802
803  /**
804   * Authenticates to the directory server using a simple bind with the provided
805   * information.
806   *
807   * @param  dn        The DN of the user for the bind.
808   * @param  password  The password to use for the bind.
809   *
810   * @throws  LDAPException  If the bind attempt fails.
811   */
812  public void bind(final String dn, final String password)
813         throws LDAPException
814  {
815    bind(3, dn, password, null);
816  }
817
818
819
820  /**
821   * Authenticates to the directory server using a simple bind with the provided
822   * information.
823   *
824   * @param  dn           The DN of the user for the bind.
825   * @param  password     The password to use for the bind.
826   * @param  constraints  The constraints to use for the bind operation.
827   *
828   * @throws  LDAPException  If the bind attempt fails.
829   */
830  public void bind(final String dn, final String password,
831                   final LDAPConstraints constraints)
832         throws LDAPException
833  {
834    bind(3, dn, password, constraints);
835  }
836
837
838
839  /**
840   * Authenticates to the directory server using a simple bind with the provided
841   * information.
842   *
843   * @param  version   The LDAP protocol version to use.  This will be ignored,
844   *                   since this implementation only supports LDAPv3.
845   * @param  dn        The DN of the user for the bind.
846   * @param  password  The password to use for the bind.
847   *
848   * @throws  LDAPException  If the bind attempt fails.
849   */
850  public void bind(final int version, final String dn, final String password)
851         throws LDAPException
852  {
853    bind(version, dn, password, null);
854  }
855
856
857
858  /**
859   * Authenticates to the directory server using a simple bind with the provided
860   * information.
861   *
862   * @param  version      The LDAP protocol version to use.  This will be
863   *                      ignored, since this implementation only supports
864   *                      LDAPv3.
865   * @param  dn           The DN of the user for the bind.
866   * @param  password     The password to use for the bind.
867   * @param  constraints  The constraints to use for the bind operation.
868   *
869   * @throws  LDAPException  If the bind attempt fails.
870   */
871  public void bind(final int version, final String dn, final String password,
872                   final LDAPConstraints constraints)
873         throws LDAPException
874  {
875    final SimpleBindRequest bindRequest =
876         new SimpleBindRequest(dn, password, getControls(constraints));
877    authDN = null;
878    authPW = null;
879
880    try
881    {
882      final BindResult bindResult = conn.bind(bindRequest);
883      setResponseControls(bindResult);
884      if (bindResult.getResultCode() == ResultCode.SUCCESS)
885      {
886        authDN = dn;
887        authPW = password;
888      }
889    }
890    catch (com.unboundid.ldap.sdk.LDAPException le)
891    {
892      debugException(le);
893      setResponseControls(le);
894      throw new LDAPException(le);
895    }
896  }
897
898
899
900  /**
901   * Indicates whether the specified entry has the given attribute value.
902   *
903   * @param  dn         The DN of the entry to compare.
904   * @param  attribute  The attribute (which must have exactly one value) to use
905   *                    for the comparison.
906   *
907   * @return  {@code true} if the compare matched the target entry, or
908   *          {@code false} if not.
909   *
910   * @throws  LDAPException  If a problem occurs while processing the compare.
911   */
912  public boolean compare(final String dn, final LDAPAttribute attribute)
913         throws LDAPException
914  {
915    return compare(dn, attribute, null);
916  }
917
918
919
920  /**
921   * Indicates whether the specified entry has the given attribute value.
922   *
923   * @param  dn           The DN of the entry to compare.
924   * @param  attribute    The attribute (which must have exactly one value) to
925   *                      use for the comparison.
926   * @param  constraints  The constraints to use for the compare operation.
927   *
928   * @return  {@code true} if the compare matched the target entry, or
929   *          {@code false} if not.
930   *
931   * @throws  LDAPException  If a problem occurs while processing the compare.
932   */
933  public boolean compare(final String dn, final LDAPAttribute attribute,
934                         final LDAPConstraints constraints)
935         throws LDAPException
936  {
937    final CompareRequest compareRequest = new CompareRequest(dn,
938         attribute.getName(), attribute.getByteValueArray()[0]);
939    update(compareRequest, constraints);
940
941    try
942    {
943      final CompareResult result = conn.compare(compareRequest);
944      setResponseControls(result);
945      return result.compareMatched();
946    }
947    catch (com.unboundid.ldap.sdk.LDAPException le)
948    {
949      debugException(le);
950      setResponseControls(le);
951      throw new LDAPException(le);
952    }
953  }
954
955
956
957  /**
958   * Removes an entry from the directory.
959   *
960   * @param  dn  The DN of the entry to delete.
961   *
962   * @throws  LDAPException  If a problem occurs while processing the delete.
963   */
964  public void delete(final String dn)
965         throws LDAPException
966  {
967    delete(dn, null);
968  }
969
970
971
972  /**
973   * Removes an entry from the directory.
974   *
975   * @param  dn           The DN of the entry to delete.
976   * @param  constraints  The constraints to use for the delete operation.
977   *
978   * @throws  LDAPException  If a problem occurs while processing the delete.
979   */
980  public void delete(final String dn, final LDAPConstraints constraints)
981         throws LDAPException
982  {
983    final DeleteRequest deleteRequest = new DeleteRequest(dn);
984    update(deleteRequest, constraints);
985
986    try
987    {
988      final LDAPResult result = conn.delete(deleteRequest);
989      setResponseControls(result);
990    }
991    catch (com.unboundid.ldap.sdk.LDAPException le)
992    {
993      debugException(le);
994      setResponseControls(le);
995      throw new LDAPException(le);
996    }
997  }
998
999
1000
1001  /**
1002   * Processes an extended operation in the directory.
1003   *
1004   * @param  extendedOperation  The extended operation to process.
1005   *
1006   * @return  The result returned from the extended operation.
1007   *
1008   * @throws  LDAPException  If a problem occurs while processing the operation.
1009   */
1010  public LDAPExtendedOperation extendedOperation(
1011              final LDAPExtendedOperation extendedOperation)
1012         throws LDAPException
1013  {
1014    return extendedOperation(extendedOperation,  null);
1015  }
1016
1017
1018
1019  /**
1020   * Processes an extended operation in the directory.
1021   *
1022   * @param  extendedOperation  The extended operation to process.
1023   * @param  constraints        The constraints to use for the operation.
1024   *
1025   * @return  The result returned from the extended operation.
1026   *
1027   * @throws  LDAPException  If a problem occurs while processing the operation.
1028   */
1029  public LDAPExtendedOperation extendedOperation(
1030              final LDAPExtendedOperation extendedOperation,
1031              final LDAPConstraints constraints)
1032         throws LDAPException
1033  {
1034    final ExtendedRequest extendedRequest = new ExtendedRequest(
1035         extendedOperation.getID(),
1036         new ASN1OctetString(extendedOperation.getValue()),
1037         getControls(constraints));
1038
1039    try
1040    {
1041      final ExtendedResult result =
1042           conn.processExtendedOperation(extendedRequest);
1043      setResponseControls(result);
1044
1045      if (result.getResultCode() != ResultCode.SUCCESS)
1046      {
1047        throw new LDAPException(result.getDiagnosticMessage(),
1048             result.getResultCode().intValue(), result.getDiagnosticMessage(),
1049             result.getMatchedDN());
1050      }
1051
1052      final byte[] valueBytes;
1053      final ASN1OctetString value = result.getValue();
1054      if (value == null)
1055      {
1056        valueBytes = null;
1057      }
1058      else
1059      {
1060        valueBytes = value.getValue();
1061      }
1062
1063      return new LDAPExtendedOperation(result.getOID(), valueBytes);
1064    }
1065    catch (com.unboundid.ldap.sdk.LDAPException le)
1066    {
1067      debugException(le);
1068      setResponseControls(le);
1069      throw new LDAPException(le);
1070    }
1071  }
1072
1073
1074
1075  /**
1076   * Modifies an entry in the directory.
1077   *
1078   * @param  dn   The DN of the entry to modify.
1079   * @param  mod  The modification to apply to the entry.
1080   *
1081   * @throws  LDAPException  If a problem occurs while processing the delete.
1082   */
1083  public void modify(final String dn, final LDAPModification mod)
1084         throws LDAPException
1085  {
1086    modify(dn, new LDAPModification[] { mod }, null);
1087  }
1088
1089
1090
1091  /**
1092   * Modifies an entry in the directory.
1093   *
1094   * @param  dn    The DN of the entry to modify.
1095   * @param  mods  The modifications to apply to the entry.
1096   *
1097   * @throws  LDAPException  If a problem occurs while processing the delete.
1098   */
1099  public void modify(final String dn, final LDAPModification[] mods)
1100         throws LDAPException
1101  {
1102    modify(dn, mods, null);
1103  }
1104
1105
1106
1107  /**
1108   * Modifies an entry in the directory.
1109   *
1110   * @param  dn           The DN of the entry to modify.
1111   * @param  mod          The modification to apply to the entry.
1112   * @param  constraints  The constraints to use for the modify operation.
1113   *
1114   * @throws  LDAPException  If a problem occurs while processing the delete.
1115   */
1116  public void modify(final String dn, final LDAPModification mod,
1117                     final LDAPConstraints constraints)
1118         throws LDAPException
1119  {
1120    modify(dn, new LDAPModification[] { mod }, constraints);
1121  }
1122
1123
1124
1125  /**
1126   * Modifies an entry in the directory.
1127   *
1128   * @param  dn           The DN of the entry to modify.
1129   * @param  mods         The modifications to apply to the entry.
1130   * @param  constraints  The constraints to use for the modify operation.
1131   *
1132   * @throws  LDAPException  If a problem occurs while processing the delete.
1133   */
1134  public void modify(final String dn, final LDAPModification[] mods,
1135                     final LDAPConstraints constraints)
1136         throws LDAPException
1137  {
1138    final Modification[] m = new Modification[mods.length];
1139    for (int i=0; i < mods.length; i++)
1140    {
1141      m[i] = mods[i].toModification();
1142    }
1143
1144    final ModifyRequest modifyRequest = new ModifyRequest(dn, m);
1145    update(modifyRequest, constraints);
1146
1147    try
1148    {
1149      final LDAPResult result = conn.modify(modifyRequest);
1150      setResponseControls(result);
1151    }
1152    catch (com.unboundid.ldap.sdk.LDAPException le)
1153    {
1154      debugException(le);
1155      setResponseControls(le);
1156      throw new LDAPException(le);
1157    }
1158  }
1159
1160
1161
1162  /**
1163   * Modifies an entry in the directory.
1164   *
1165   * @param  dn    The DN of the entry to modify.
1166   * @param  mods  The modifications to apply to the entry.
1167   *
1168   * @throws  LDAPException  If a problem occurs while processing the delete.
1169   */
1170  public void modify(final String dn, final LDAPModificationSet mods)
1171         throws LDAPException
1172  {
1173    modify(dn, mods.toArray(), null);
1174  }
1175
1176
1177
1178  /**
1179   * Modifies an entry in the directory.
1180   *
1181   * @param  dn           The DN of the entry to modify.
1182   * @param  mods         The modifications to apply to the entry.
1183   * @param  constraints  The constraints to use for the modify operation.
1184   *
1185   * @throws  LDAPException  If a problem occurs while processing the delete.
1186   */
1187  public void modify(final String dn, final LDAPModificationSet mods,
1188                     final LDAPConstraints constraints)
1189         throws LDAPException
1190  {
1191    modify(dn, mods.toArray(), constraints);
1192  }
1193
1194
1195
1196  /**
1197   * Retrieves an entry from the directory server.
1198   *
1199   * @param  dn  The DN of the entry to retrieve.
1200   *
1201   * @return  The entry that was read.
1202   *
1203   * @throws  LDAPException  If a problem occurs while performing the search.
1204   */
1205  public LDAPEntry read(final String dn)
1206         throws LDAPException
1207  {
1208    return read(dn, null, null);
1209  }
1210
1211
1212
1213  /**
1214   * Retrieves an entry from the directory server.
1215   *
1216   * @param  dn           The DN of the entry to retrieve.
1217   * @param  constraints  The constraints to use for the search operation.
1218   *
1219   * @return  The entry that was read.
1220   *
1221   * @throws  LDAPException  If a problem occurs while performing the search.
1222   */
1223  public LDAPEntry read(final String dn,
1224                        final LDAPSearchConstraints constraints)
1225         throws LDAPException
1226  {
1227    return read(dn, null, constraints);
1228  }
1229
1230
1231
1232  /**
1233   * Retrieves an entry from the directory server.
1234   *
1235   * @param  dn     The DN of the entry to retrieve.
1236   * @param  attrs  The set of attributes to request.
1237   *
1238   * @return  The entry that was read.
1239   *
1240   * @throws  LDAPException  If a problem occurs while performing the search.
1241   */
1242  public LDAPEntry read(final String dn, final String[] attrs)
1243         throws LDAPException
1244  {
1245    return read(dn, attrs, null);
1246  }
1247
1248
1249
1250  /**
1251   * Retrieves an entry from the directory server.
1252   *
1253   * @param  dn           The DN of the entry to retrieve.
1254   * @param  attrs        The set of attributes to request.
1255   * @param  constraints  The constraints to use for the search operation.
1256   *
1257   * @return  The entry that was read.
1258   *
1259   * @throws  LDAPException  If a problem occurs while performing the search.
1260   */
1261  public LDAPEntry read(final String dn, final String[] attrs,
1262                        final LDAPSearchConstraints constraints)
1263         throws LDAPException
1264  {
1265    final Filter filter = Filter.createORFilter(
1266         Filter.createPresenceFilter("objectClass"),
1267         Filter.createEqualityFilter("objectClass", "ldapSubentry"));
1268
1269    final SearchRequest searchRequest =
1270         new SearchRequest(dn, SearchScope.BASE, filter, attrs);
1271    update(searchRequest, constraints);
1272
1273    try
1274    {
1275      final SearchResult searchResult = conn.search(searchRequest);
1276      setResponseControls(searchResult);
1277
1278      if (searchResult.getEntryCount() != 1)
1279      {
1280        throw new LDAPException(null, LDAPException.NO_RESULTS_RETURNED);
1281      }
1282
1283      return new LDAPEntry(searchResult.getSearchEntries().get(0));
1284    }
1285    catch (com.unboundid.ldap.sdk.LDAPException le)
1286    {
1287      debugException(le);
1288      setResponseControls(le);
1289      throw new LDAPException(le);
1290    }
1291  }
1292
1293
1294
1295  /**
1296   * Alters the DN of an entry in the directory.
1297   *
1298   * @param  dn            The DN of the entry to modify.
1299   * @param  newRDN        The new RDN to use for the entry.
1300   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1301   *
1302   * @throws  LDAPException  If a problem occurs while processing the delete.
1303   */
1304  public void rename(final String dn, final String newRDN,
1305                     final boolean deleteOldRDN)
1306         throws LDAPException
1307  {
1308    rename(dn, newRDN, null, deleteOldRDN, null);
1309  }
1310
1311
1312
1313  /**
1314   * Alters the DN of an entry in the directory.
1315   *
1316   * @param  dn            The DN of the entry to modify.
1317   * @param  newRDN        The new RDN to use for the entry.
1318   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1319   * @param  constraints   The constraints to use for the modify operation.
1320   *
1321   * @throws  LDAPException  If a problem occurs while processing the delete.
1322   */
1323  public void rename(final String dn, final String newRDN,
1324                     final boolean deleteOldRDN,
1325                     final LDAPConstraints constraints)
1326         throws LDAPException
1327  {
1328    rename(dn, newRDN, null, deleteOldRDN, constraints);
1329  }
1330
1331
1332
1333  /**
1334   * Alters the DN of an entry in the directory.
1335   *
1336   * @param  dn            The DN of the entry to modify.
1337   * @param  newRDN        The new RDN to use for the entry.
1338   * @param  newParentDN   The DN of the new parent, or {@code null} if it
1339   *                       should not be moved below a new parent.
1340   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1341   *
1342   * @throws  LDAPException  If a problem occurs while processing the delete.
1343   */
1344  public void rename(final String dn, final String newRDN,
1345                     final String newParentDN, final boolean deleteOldRDN)
1346         throws LDAPException
1347  {
1348    rename(dn, newRDN, newParentDN, deleteOldRDN, null);
1349  }
1350
1351
1352
1353  /**
1354   * Alters the DN of an entry in the directory.
1355   *
1356   * @param  dn            The DN of the entry to modify.
1357   * @param  newRDN        The new RDN to use for the entry.
1358   * @param  newParentDN   The DN of the new parent, or {@code null} if it
1359   *                       should not be moved below a new parent.
1360   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1361   * @param  constraints   The constraints to use for the modify operation.
1362   *
1363   * @throws  LDAPException  If a problem occurs while processing the delete.
1364   */
1365  public void rename(final String dn, final String newRDN,
1366                     final String newParentDN, final boolean deleteOldRDN,
1367                     final LDAPConstraints constraints)
1368         throws LDAPException
1369  {
1370    final ModifyDNRequest modifyDNRequest =
1371         new ModifyDNRequest(dn, newRDN, deleteOldRDN, newParentDN);
1372    update(modifyDNRequest, constraints);
1373
1374    try
1375    {
1376      final LDAPResult result = conn.modifyDN(modifyDNRequest);
1377      setResponseControls(result);
1378    }
1379    catch (com.unboundid.ldap.sdk.LDAPException le)
1380    {
1381      debugException(le);
1382      setResponseControls(le);
1383      throw new LDAPException(le);
1384    }
1385  }
1386
1387
1388
1389  /**
1390   * Processes a search in the directory server.
1391   *
1392   * @param  baseDN       The base DN for the search.
1393   * @param  scope        The scope for the search.
1394   * @param  filter       The filter for the search.
1395   * @param  attributes   The set of attributes to request.
1396   * @param  typesOnly    Indicates whether to return attribute types only or
1397   *                      both types and values.
1398   *
1399   * @return  The entry that was read.
1400   *
1401   * @throws  LDAPException  If a problem occurs while performing the search.
1402   */
1403  public LDAPSearchResults search(final String baseDN, final int scope,
1404              final String filter, final String[] attributes,
1405              final boolean typesOnly)
1406         throws LDAPException
1407  {
1408    return search(baseDN, scope, filter, attributes, typesOnly, null);
1409  }
1410
1411
1412
1413  /**
1414   * Processes a search in the directory server.
1415   *
1416   * @param  baseDN       The base DN for the search.
1417   * @param  scope        The scope for the search.
1418   * @param  filter       The filter for the search.
1419   * @param  attributes   The set of attributes to request.
1420   * @param  typesOnly    Indicates whether to return attribute types only or
1421   *                      both types and values.
1422   * @param  constraints  The constraints to use for the search operation.
1423   *
1424   * @return  The entry that was read.
1425   *
1426   * @throws  LDAPException  If a problem occurs while performing the search.
1427   */
1428  public LDAPSearchResults search(final String baseDN, final int scope,
1429              final String filter, final String[] attributes,
1430              final boolean typesOnly, final LDAPSearchConstraints constraints)
1431         throws LDAPException
1432  {
1433    final LDAPSearchResults results;
1434    final LDAPSearchConstraints c =
1435         (constraints == null) ? searchConstraints : constraints;
1436    results = new LDAPSearchResults(c.getTimeLimit());
1437
1438    try
1439    {
1440      final SearchRequest searchRequest = new SearchRequest(results, baseDN,
1441           SearchScope.valueOf(scope), filter, attributes);
1442
1443      searchRequest.setDerefPolicy(
1444           DereferencePolicy.valueOf(c.getDereference()));
1445      searchRequest.setSizeLimit(c.getMaxResults());
1446      searchRequest.setTimeLimitSeconds(c.getServerTimeLimit());
1447      searchRequest.setTypesOnly(typesOnly);
1448
1449      update(searchRequest, constraints);
1450
1451      conn.asyncSearch(searchRequest);
1452      return results;
1453    }
1454    catch (com.unboundid.ldap.sdk.LDAPException le)
1455    {
1456      debugException(le);
1457      setResponseControls(le);
1458      throw new LDAPException(le);
1459    }
1460  }
1461
1462
1463
1464  /**
1465   * Retrieves the set of controls to use in a request.
1466   *
1467   * @param  c  The constraints to be applied.
1468   *
1469   * @return  The set of controls to use in a request.
1470   */
1471  private Control[] getControls(final LDAPConstraints c)
1472  {
1473    Control[] controls = null;
1474    if (c != null)
1475    {
1476      controls = LDAPControl.toControls(c.getServerControls());
1477    }
1478    else if (constraints != null)
1479    {
1480      controls = LDAPControl.toControls(constraints.getServerControls());
1481    }
1482
1483    if (controls == null)
1484    {
1485      return new Control[0];
1486    }
1487    else
1488    {
1489      return controls;
1490    }
1491  }
1492
1493
1494
1495  /**
1496   * Updates the provided request to account for the given set of constraints.
1497   *
1498   * @param  request      The request to be updated.
1499   * @param  constraints  The constraints to be applied.
1500   */
1501  private void update(final UpdatableLDAPRequest request,
1502                      final LDAPConstraints constraints)
1503  {
1504    final LDAPConstraints c =
1505         (constraints == null) ? this.constraints : constraints;
1506
1507    request.setControls(LDAPControl.toControls(c.getServerControls()));
1508    request.setResponseTimeoutMillis(c.getTimeLimit());
1509    request.setFollowReferrals(c.getReferrals());
1510  }
1511
1512
1513
1514  /**
1515   * Sets the response controls for this connection.
1516   *
1517   * @param  ldapResult  The result containing the controls to use.
1518   */
1519  private void setResponseControls(final LDAPResult ldapResult)
1520  {
1521    if (ldapResult.hasResponseControl())
1522    {
1523      responseControls =
1524           LDAPControl.toLDAPControls(ldapResult.getResponseControls());
1525    }
1526    else
1527    {
1528      responseControls = null;
1529    }
1530  }
1531
1532
1533
1534  /**
1535   * Sets the response controls for this connection.
1536   *
1537   * @param  ldapException  The exception containing the controls to use.
1538   */
1539  private void setResponseControls(
1540                    final com.unboundid.ldap.sdk.LDAPException ldapException)
1541  {
1542    if (ldapException.hasResponseControl())
1543    {
1544      responseControls =
1545           LDAPControl.toLDAPControls(ldapException.getResponseControls());
1546    }
1547    else
1548    {
1549      responseControls = null;
1550    }
1551  }
1552}