001/*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-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.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 final 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.connect(host, port);
460    }
461    catch (com.unboundid.ldap.sdk.LDAPException le)
462    {
463      debugException(le);
464      throw new LDAPException(le);
465    }
466  }
467
468
469
470  /**
471   * Attempts to establish and authenticate this connection with the provided
472   * information.
473   *
474   * @param  host      The address of the server to which the connection should
475   *                   be established.
476   * @param  port      The port of the server to which the connection should be
477   *                   established.
478   * @param  dn        The DN to use to bind to the server.
479   * @param  password  The password to use to bind to the server.
480   *
481   * @throws  LDAPException  If a problem occurs while attempting to establish
482   *                         or authenticate this connection.  If an exception
483   *                         is thrown, then the connection will not be
484   *                         established.
485   */
486  public void connect(final String host, final int port, final String dn,
487                      final String password)
488         throws LDAPException
489  {
490    connect(3, host, port, dn, password, null);
491  }
492
493
494
495  /**
496   * Attempts to establish and authenticate this connection with the provided
497   * information.
498   *
499   * @param  host         The address of the server to which the connection
500   *                      should be established.
501   * @param  port         The port of the server to which the connection should
502   *                      be established.
503   * @param  dn           The DN to use to bind to the server.
504   * @param  password     The password to use to bind to the server.
505   * @param  constraints  The constraints to use when processing the bind.
506   *
507   * @throws  LDAPException  If a problem occurs while attempting to establish
508   *                         or authenticate this connection.  If an exception
509   *                         is thrown, then the connection will not be
510   *                         established.
511   */
512  public void connect(final String host, final int port, final String dn,
513                      final String password, final LDAPConstraints constraints)
514         throws LDAPException
515  {
516    connect(3, host, port, dn, password, constraints);
517  }
518
519
520
521  /**
522   * Attempts to establish and authenticate this connection with the provided
523   * information.
524   *
525   * @param  version   The LDAP protocol version to use for the connection.
526   *                   This will be ignored, since this implementation only
527   *                   supports LDAPv3.
528   * @param  host      The address of the server to which the connection should
529   *                   be established.
530   * @param  port      The port of the server to which the connection should be
531   *                   established.
532   * @param  dn        The DN to use to bind to the server.
533   * @param  password  The password to use to bind to the server.
534   *
535   * @throws  LDAPException  If a problem occurs while attempting to establish
536   *                         or authenticate this connection.  If an exception
537   *                         is thrown, then the connection will not be
538   *                         established.
539   */
540  public void connect(final int version, final String host, final int port,
541                      final String dn, final String password)
542         throws LDAPException
543  {
544    connect(version, host, port, dn, password, null);
545  }
546
547
548
549  /**
550   * Attempts to establish and authenticate this connection with the provided
551   * information.
552   *
553   * @param  version      The LDAP protocol version to use for the connection.
554   *                      This will be ignored, since this implementation only
555   *                      supports LDAPv3.
556   * @param  host         The address of the server to which the connection
557   *                      should be established.
558   * @param  port         The port of the server to which the connection should
559   *                      be established.
560   * @param  dn           The DN to use to bind to the server.
561   * @param  password     The password to use to bind to the server.
562   * @param  constraints  The constraints to use when processing the bind.
563   *
564   * @throws  LDAPException  If a problem occurs while attempting to establish
565   *                         or authenticate this connection.  If an exception
566   *                         is thrown, then the connection will not be
567   *                         established.
568   */
569  public void connect(final int version, final String host, final int port,
570                      final String dn, final String password,
571                      final LDAPConstraints constraints)
572         throws LDAPException
573  {
574    connect(host, port);
575
576    try
577    {
578      if ((dn != null) && (password != null))
579      {
580        bind(version, dn, password, constraints);
581      }
582    }
583    catch (LDAPException le)
584    {
585      conn.close();
586      throw le;
587    }
588  }
589
590
591
592  /**
593   * Unbinds and disconnects from the directory server.
594   *
595   * @throws  LDAPException  If a problem occurs.
596   */
597  public void disconnect()
598         throws LDAPException
599  {
600    conn.close();
601    authDN = null;
602    authPW = null;
603  }
604
605
606
607  /**
608   * Disconnects from the directory server and attempts to re-connect and
609   * re-authenticate.
610   *
611   * @throws  LDAPException  If a problem occurs.  If an exception is thrown,
612   *                         the connection will have been closed.
613   */
614  public void reconnect()
615         throws LDAPException
616  {
617    final String host = getHost();
618    final int    port = getPort();
619    final String dn   = authDN;
620    final String pw   = authPW;
621
622    conn.close();
623
624    if ((dn == null) || (pw == null))
625    {
626      connect(host, port);
627    }
628    else
629    {
630      connect(host, port, dn, pw);
631    }
632  }
633
634
635
636  /**
637   * Sends a request to abandon the request with the specified message ID.
638   *
639   * @param  id  The message ID of the operation to abandon.
640   *
641   * @throws  LDAPException  If a problem occurs while sending the request.
642   */
643  public void abandon(final int id)
644         throws LDAPException
645  {
646    try
647    {
648      conn.abandon(InternalSDKHelper.createAsyncRequestID(id, conn),
649                   getControls(null));
650    }
651    catch (com.unboundid.ldap.sdk.LDAPException le)
652    {
653      debugException(le);
654      throw new LDAPException(le);
655    }
656  }
657
658
659
660  /**
661   * Adds the provided entry to the directory.
662   *
663   * @param  entry  The entry to be added.
664   *
665   * @throws  LDAPException  If a problem occurs while adding the entry.
666   */
667  public void add(final LDAPEntry entry)
668         throws LDAPException
669  {
670    add(entry, null);
671  }
672
673
674
675  /**
676   * Adds the provided entry to the directory.
677   *
678   * @param  entry        The entry to be added.
679   * @param  constraints  The constraints to use for the add operation.
680   *
681   * @throws  LDAPException  If a problem occurs while adding the entry.
682   */
683  public void add(final LDAPEntry entry, final LDAPConstraints constraints)
684         throws LDAPException
685  {
686    final AddRequest addRequest = new AddRequest(entry.toEntry());
687    update(addRequest, constraints);
688
689    try
690    {
691      final LDAPResult result = conn.add(addRequest);
692      setResponseControls(result);
693    }
694    catch (com.unboundid.ldap.sdk.LDAPException le)
695    {
696      debugException(le);
697      setResponseControls(le);
698      throw new LDAPException(le);
699    }
700  }
701
702
703
704
705  /**
706   * Authenticates to the directory server using a simple bind with the provided
707   * information.
708   *
709   * @param  dn        The DN of the user for the bind.
710   * @param  password  The password to use for the bind.
711   *
712   * @throws  LDAPException  If the bind attempt fails.
713   */
714  public void authenticate(final String dn, final String password)
715         throws LDAPException
716  {
717    bind(3, dn, password, null);
718  }
719
720
721
722  /**
723   * Authenticates to the directory server using a simple bind with the provided
724   * information.
725   *
726   * @param  dn           The DN of the user for the bind.
727   * @param  password     The password to use for the bind.
728   * @param  constraints  The constraints to use for the bind operation.
729   *
730   * @throws  LDAPException  If the bind attempt fails.
731   */
732  public void authenticate(final String dn, final String password,
733                           final LDAPConstraints constraints)
734         throws LDAPException
735  {
736    bind(3, dn, password, constraints);
737  }
738
739
740
741  /**
742   * Authenticates to the directory server using a simple bind with the provided
743   * information.
744   *
745   * @param  version   The LDAP protocol version to use.  This will be ignored,
746   *                   since this implementation only supports LDAPv3.
747   * @param  dn        The DN of the user for the bind.
748   * @param  password  The password to use for the bind.
749   *
750   * @throws  LDAPException  If the bind attempt fails.
751   */
752  public void authenticate(final int version, final String dn,
753                           final String password)
754         throws LDAPException
755  {
756    bind(version, dn, password, null);
757  }
758
759
760
761  /**
762   * Authenticates to the directory server using a simple bind with the provided
763   * information.
764   *
765   * @param  version      The LDAP protocol version to use.  This will be
766   *                      ignored, since this implementation only supports
767   *                      LDAPv3.
768   * @param  dn           The DN of the user for the bind.
769   * @param  password     The password to use for the bind.
770   * @param  constraints  The constraints to use for the bind operation.
771   *
772   * @throws  LDAPException  If the bind attempt fails.
773   */
774  public void authenticate(final int version, final String dn,
775                           final String password,
776                           final LDAPConstraints constraints)
777         throws LDAPException
778  {
779    bind(version, dn, password, constraints);
780  }
781
782
783
784  /**
785   * Authenticates to the directory server using a simple bind with the provided
786   * information.
787   *
788   * @param  dn        The DN of the user for the bind.
789   * @param  password  The password to use for the bind.
790   *
791   * @throws  LDAPException  If the bind attempt fails.
792   */
793  public void bind(final String dn, final String password)
794         throws LDAPException
795  {
796    bind(3, dn, password, null);
797  }
798
799
800
801  /**
802   * Authenticates to the directory server using a simple bind with the provided
803   * information.
804   *
805   * @param  dn           The DN of the user for the bind.
806   * @param  password     The password to use for the bind.
807   * @param  constraints  The constraints to use for the bind operation.
808   *
809   * @throws  LDAPException  If the bind attempt fails.
810   */
811  public void bind(final String dn, final String password,
812                   final LDAPConstraints constraints)
813         throws LDAPException
814  {
815    bind(3, dn, password, constraints);
816  }
817
818
819
820  /**
821   * Authenticates to the directory server using a simple bind with the provided
822   * information.
823   *
824   * @param  version   The LDAP protocol version to use.  This will be ignored,
825   *                   since this implementation only supports LDAPv3.
826   * @param  dn        The DN of the user for the bind.
827   * @param  password  The password to use for the bind.
828   *
829   * @throws  LDAPException  If the bind attempt fails.
830   */
831  public void bind(final int version, final String dn, final String password)
832         throws LDAPException
833  {
834    bind(version, dn, password, null);
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
844   *                      ignored, since this implementation only supports
845   *                      LDAPv3.
846   * @param  dn           The DN of the user for the bind.
847   * @param  password     The password to use for the bind.
848   * @param  constraints  The constraints to use for the bind operation.
849   *
850   * @throws  LDAPException  If the bind attempt fails.
851   */
852  public void bind(final int version, final String dn, final String password,
853                   final LDAPConstraints constraints)
854         throws LDAPException
855  {
856    final SimpleBindRequest bindRequest =
857         new SimpleBindRequest(dn, password, getControls(constraints));
858    authDN = null;
859    authPW = null;
860
861    try
862    {
863      final BindResult bindResult = conn.bind(bindRequest);
864      setResponseControls(bindResult);
865      if (bindResult.getResultCode() == ResultCode.SUCCESS)
866      {
867        authDN = dn;
868        authPW = password;
869      }
870    }
871    catch (com.unboundid.ldap.sdk.LDAPException le)
872    {
873      debugException(le);
874      setResponseControls(le);
875      throw new LDAPException(le);
876    }
877  }
878
879
880
881  /**
882   * Indicates whether the specified entry has the given attribute value.
883   *
884   * @param  dn         The DN of the entry to compare.
885   * @param  attribute  The attribute (which must have exactly one value) to use
886   *                    for the comparison.
887   *
888   * @return  {@code true} if the compare matched the target entry, or
889   *          {@code false} if not.
890   *
891   * @throws  LDAPException  If a problem occurs while processing the compare.
892   */
893  public boolean compare(final String dn, final LDAPAttribute attribute)
894         throws LDAPException
895  {
896    return compare(dn, attribute, null);
897  }
898
899
900
901  /**
902   * Indicates whether the specified entry has the given attribute value.
903   *
904   * @param  dn           The DN of the entry to compare.
905   * @param  attribute    The attribute (which must have exactly one value) to
906   *                      use for the comparison.
907   * @param  constraints  The constraints to use for the compare operation.
908   *
909   * @return  {@code true} if the compare matched the target entry, or
910   *          {@code false} if not.
911   *
912   * @throws  LDAPException  If a problem occurs while processing the compare.
913   */
914  public boolean compare(final String dn, final LDAPAttribute attribute,
915                         final LDAPConstraints constraints)
916         throws LDAPException
917  {
918    final CompareRequest compareRequest = new CompareRequest(dn,
919         attribute.getName(), attribute.getByteValueArray()[0]);
920    update(compareRequest, constraints);
921
922    try
923    {
924      final CompareResult result = conn.compare(compareRequest);
925      setResponseControls(result);
926      return result.compareMatched();
927    }
928    catch (com.unboundid.ldap.sdk.LDAPException le)
929    {
930      debugException(le);
931      setResponseControls(le);
932      throw new LDAPException(le);
933    }
934  }
935
936
937
938  /**
939   * Removes an entry from the directory.
940   *
941   * @param  dn  The DN of the entry to delete.
942   *
943   * @throws  LDAPException  If a problem occurs while processing the delete.
944   */
945  public void delete(final String dn)
946         throws LDAPException
947  {
948    delete(dn, null);
949  }
950
951
952
953  /**
954   * Removes an entry from the directory.
955   *
956   * @param  dn           The DN of the entry to delete.
957   * @param  constraints  The constraints to use for the delete operation.
958   *
959   * @throws  LDAPException  If a problem occurs while processing the delete.
960   */
961  public void delete(final String dn, final LDAPConstraints constraints)
962         throws LDAPException
963  {
964    final DeleteRequest deleteRequest = new DeleteRequest(dn);
965    update(deleteRequest, constraints);
966
967    try
968    {
969      final LDAPResult result = conn.delete(deleteRequest);
970      setResponseControls(result);
971    }
972    catch (com.unboundid.ldap.sdk.LDAPException le)
973    {
974      debugException(le);
975      setResponseControls(le);
976      throw new LDAPException(le);
977    }
978  }
979
980
981
982  /**
983   * Processes an extended operation in the directory.
984   *
985   * @param  extendedOperation  The extended operation to process.
986   *
987   * @return  The result returned from the extended operation.
988   *
989   * @throws  LDAPException  If a problem occurs while processing the operation.
990   */
991  public LDAPExtendedOperation extendedOperation(
992              final LDAPExtendedOperation extendedOperation)
993         throws LDAPException
994  {
995    return extendedOperation(extendedOperation,  null);
996  }
997
998
999
1000  /**
1001   * Processes an extended operation in the directory.
1002   *
1003   * @param  extendedOperation  The extended operation to process.
1004   * @param  constraints        The constraints to use for the operation.
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              final LDAPConstraints constraints)
1013         throws LDAPException
1014  {
1015    final ExtendedRequest extendedRequest = new ExtendedRequest(
1016         extendedOperation.getID(),
1017         new ASN1OctetString(extendedOperation.getValue()),
1018         getControls(constraints));
1019
1020    try
1021    {
1022      final ExtendedResult result =
1023           conn.processExtendedOperation(extendedRequest);
1024      setResponseControls(result);
1025
1026      if (result.getResultCode() != ResultCode.SUCCESS)
1027      {
1028        throw new LDAPException(result.getDiagnosticMessage(),
1029             result.getResultCode().intValue(), result.getDiagnosticMessage(),
1030             result.getMatchedDN());
1031      }
1032
1033      final byte[] valueBytes;
1034      final ASN1OctetString value = result.getValue();
1035      if (value == null)
1036      {
1037        valueBytes = null;
1038      }
1039      else
1040      {
1041        valueBytes = value.getValue();
1042      }
1043
1044      return new LDAPExtendedOperation(result.getOID(), valueBytes);
1045    }
1046    catch (com.unboundid.ldap.sdk.LDAPException le)
1047    {
1048      debugException(le);
1049      setResponseControls(le);
1050      throw new LDAPException(le);
1051    }
1052  }
1053
1054
1055
1056  /**
1057   * Modifies an entry in the directory.
1058   *
1059   * @param  dn   The DN of the entry to modify.
1060   * @param  mod  The modification to apply to the entry.
1061   *
1062   * @throws  LDAPException  If a problem occurs while processing the delete.
1063   */
1064  public void modify(final String dn, final LDAPModification mod)
1065         throws LDAPException
1066  {
1067    modify(dn, new LDAPModification[] { mod }, null);
1068  }
1069
1070
1071
1072  /**
1073   * Modifies an entry in the directory.
1074   *
1075   * @param  dn    The DN of the entry to modify.
1076   * @param  mods  The modifications to apply to the entry.
1077   *
1078   * @throws  LDAPException  If a problem occurs while processing the delete.
1079   */
1080  public void modify(final String dn, final LDAPModification[] mods)
1081         throws LDAPException
1082  {
1083    modify(dn, mods, null);
1084  }
1085
1086
1087
1088  /**
1089   * Modifies an entry in the directory.
1090   *
1091   * @param  dn           The DN of the entry to modify.
1092   * @param  mod          The modification to apply to the entry.
1093   * @param  constraints  The constraints to use for the modify operation.
1094   *
1095   * @throws  LDAPException  If a problem occurs while processing the delete.
1096   */
1097  public void modify(final String dn, final LDAPModification mod,
1098                     final LDAPConstraints constraints)
1099         throws LDAPException
1100  {
1101    modify(dn, new LDAPModification[] { mod }, constraints);
1102  }
1103
1104
1105
1106  /**
1107   * Modifies an entry in the directory.
1108   *
1109   * @param  dn           The DN of the entry to modify.
1110   * @param  mods         The modifications to apply to the entry.
1111   * @param  constraints  The constraints to use for the modify operation.
1112   *
1113   * @throws  LDAPException  If a problem occurs while processing the delete.
1114   */
1115  public void modify(final String dn, final LDAPModification[] mods,
1116                     final LDAPConstraints constraints)
1117         throws LDAPException
1118  {
1119    final Modification[] m = new Modification[mods.length];
1120    for (int i=0; i < mods.length; i++)
1121    {
1122      m[i] = mods[i].toModification();
1123    }
1124
1125    final ModifyRequest modifyRequest = new ModifyRequest(dn, m);
1126    update(modifyRequest, constraints);
1127
1128    try
1129    {
1130      final LDAPResult result = conn.modify(modifyRequest);
1131      setResponseControls(result);
1132    }
1133    catch (com.unboundid.ldap.sdk.LDAPException le)
1134    {
1135      debugException(le);
1136      setResponseControls(le);
1137      throw new LDAPException(le);
1138    }
1139  }
1140
1141
1142
1143  /**
1144   * Modifies an entry in the directory.
1145   *
1146   * @param  dn    The DN of the entry to modify.
1147   * @param  mods  The modifications to apply to the entry.
1148   *
1149   * @throws  LDAPException  If a problem occurs while processing the delete.
1150   */
1151  public void modify(final String dn, final LDAPModificationSet mods)
1152         throws LDAPException
1153  {
1154    modify(dn, mods.toArray(), null);
1155  }
1156
1157
1158
1159  /**
1160   * Modifies an entry in the directory.
1161   *
1162   * @param  dn           The DN of the entry to modify.
1163   * @param  mods         The modifications to apply to the entry.
1164   * @param  constraints  The constraints to use for the modify operation.
1165   *
1166   * @throws  LDAPException  If a problem occurs while processing the delete.
1167   */
1168  public void modify(final String dn, final LDAPModificationSet mods,
1169                     final LDAPConstraints constraints)
1170         throws LDAPException
1171  {
1172    modify(dn, mods.toArray(), constraints);
1173  }
1174
1175
1176
1177  /**
1178   * Retrieves an entry from the directory server.
1179   *
1180   * @param  dn  The DN of the entry to retrieve.
1181   *
1182   * @return  The entry that was read.
1183   *
1184   * @throws  LDAPException  If a problem occurs while performing the search.
1185   */
1186  public LDAPEntry read(final String dn)
1187         throws LDAPException
1188  {
1189    return read(dn, null, null);
1190  }
1191
1192
1193
1194  /**
1195   * Retrieves an entry from the directory server.
1196   *
1197   * @param  dn           The DN of the entry to retrieve.
1198   * @param  constraints  The constraints to use for the search operation.
1199   *
1200   * @return  The entry that was read.
1201   *
1202   * @throws  LDAPException  If a problem occurs while performing the search.
1203   */
1204  public LDAPEntry read(final String dn,
1205                        final LDAPSearchConstraints constraints)
1206         throws LDAPException
1207  {
1208    return read(dn, null, constraints);
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  attrs  The set of attributes to request.
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, final String[] attrs)
1224         throws LDAPException
1225  {
1226    return read(dn, attrs, null);
1227  }
1228
1229
1230
1231  /**
1232   * Retrieves an entry from the directory server.
1233   *
1234   * @param  dn           The DN of the entry to retrieve.
1235   * @param  attrs        The set of attributes to request.
1236   * @param  constraints  The constraints to use for the search operation.
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                        final LDAPSearchConstraints constraints)
1244         throws LDAPException
1245  {
1246    final Filter filter = Filter.createORFilter(
1247         Filter.createPresenceFilter("objectClass"),
1248         Filter.createEqualityFilter("objectClass", "ldapSubentry"));
1249
1250    final SearchRequest searchRequest =
1251         new SearchRequest(dn, SearchScope.BASE, filter, attrs);
1252    update(searchRequest, constraints);
1253
1254    try
1255    {
1256      final SearchResult searchResult = conn.search(searchRequest);
1257      setResponseControls(searchResult);
1258
1259      if (searchResult.getEntryCount() != 1)
1260      {
1261        throw new LDAPException(null, LDAPException.NO_RESULTS_RETURNED);
1262      }
1263
1264      return new LDAPEntry(searchResult.getSearchEntries().get(0));
1265    }
1266    catch (com.unboundid.ldap.sdk.LDAPException le)
1267    {
1268      debugException(le);
1269      setResponseControls(le);
1270      throw new LDAPException(le);
1271    }
1272  }
1273
1274
1275
1276  /**
1277   * Alters the DN of an entry in the directory.
1278   *
1279   * @param  dn            The DN of the entry to modify.
1280   * @param  newRDN        The new RDN to use for the entry.
1281   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1282   *
1283   * @throws  LDAPException  If a problem occurs while processing the delete.
1284   */
1285  public void rename(final String dn, final String newRDN,
1286                     final boolean deleteOldRDN)
1287         throws LDAPException
1288  {
1289    rename(dn, newRDN, null, deleteOldRDN, null);
1290  }
1291
1292
1293
1294  /**
1295   * Alters the DN of an entry in the directory.
1296   *
1297   * @param  dn            The DN of the entry to modify.
1298   * @param  newRDN        The new RDN to use for the entry.
1299   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1300   * @param  constraints   The constraints to use for the modify operation.
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                     final LDAPConstraints constraints)
1307         throws LDAPException
1308  {
1309    rename(dn, newRDN, null, deleteOldRDN, constraints);
1310  }
1311
1312
1313
1314  /**
1315   * Alters the DN of an entry in the directory.
1316   *
1317   * @param  dn            The DN of the entry to modify.
1318   * @param  newRDN        The new RDN to use for the entry.
1319   * @param  newParentDN   The DN of the new parent, or {@code null} if it
1320   *                       should not be moved below a new parent.
1321   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1322   *
1323   * @throws  LDAPException  If a problem occurs while processing the delete.
1324   */
1325  public void rename(final String dn, final String newRDN,
1326                     final String newParentDN, final boolean deleteOldRDN)
1327         throws LDAPException
1328  {
1329    rename(dn, newRDN, newParentDN, deleteOldRDN, null);
1330  }
1331
1332
1333
1334  /**
1335   * Alters the DN of an entry in the directory.
1336   *
1337   * @param  dn            The DN of the entry to modify.
1338   * @param  newRDN        The new RDN to use for the entry.
1339   * @param  newParentDN   The DN of the new parent, or {@code null} if it
1340   *                       should not be moved below a new parent.
1341   * @param  deleteOldRDN  Indicates whether to remove the old RDN value(s).
1342   * @param  constraints   The constraints to use for the modify operation.
1343   *
1344   * @throws  LDAPException  If a problem occurs while processing the delete.
1345   */
1346  public void rename(final String dn, final String newRDN,
1347                     final String newParentDN, final boolean deleteOldRDN,
1348                     final LDAPConstraints constraints)
1349         throws LDAPException
1350  {
1351    final ModifyDNRequest modifyDNRequest =
1352         new ModifyDNRequest(dn, newRDN, deleteOldRDN, newParentDN);
1353    update(modifyDNRequest, constraints);
1354
1355    try
1356    {
1357      final LDAPResult result = conn.modifyDN(modifyDNRequest);
1358      setResponseControls(result);
1359    }
1360    catch (com.unboundid.ldap.sdk.LDAPException le)
1361    {
1362      debugException(le);
1363      setResponseControls(le);
1364      throw new LDAPException(le);
1365    }
1366  }
1367
1368
1369
1370  /**
1371   * Processes a search in the directory server.
1372   *
1373   * @param  baseDN       The base DN for the search.
1374   * @param  scope        The scope for the search.
1375   * @param  filter       The filter for the search.
1376   * @param  attributes   The set of attributes to request.
1377   * @param  typesOnly    Indicates whether to return attribute types only or
1378   *                      both types and values.
1379   *
1380   * @return  The entry that was read.
1381   *
1382   * @throws  LDAPException  If a problem occurs while performing the search.
1383   */
1384  public LDAPSearchResults search(final String baseDN, final int scope,
1385              final String filter, final String[] attributes,
1386              final boolean typesOnly)
1387         throws LDAPException
1388  {
1389    return search(baseDN, scope, filter, attributes, typesOnly, null);
1390  }
1391
1392
1393
1394  /**
1395   * Processes a search in the directory server.
1396   *
1397   * @param  baseDN       The base DN for the search.
1398   * @param  scope        The scope for the search.
1399   * @param  filter       The filter for the search.
1400   * @param  attributes   The set of attributes to request.
1401   * @param  typesOnly    Indicates whether to return attribute types only or
1402   *                      both types and values.
1403   * @param  constraints  The constraints to use for the search operation.
1404   *
1405   * @return  The entry that was read.
1406   *
1407   * @throws  LDAPException  If a problem occurs while performing the search.
1408   */
1409  public LDAPSearchResults search(final String baseDN, final int scope,
1410              final String filter, final String[] attributes,
1411              final boolean typesOnly, final LDAPSearchConstraints constraints)
1412         throws LDAPException
1413  {
1414    final LDAPSearchResults results;
1415    final LDAPSearchConstraints c =
1416         (constraints == null) ? searchConstraints : constraints;
1417    results = new LDAPSearchResults(c.getTimeLimit());
1418
1419    try
1420    {
1421      final SearchRequest searchRequest = new SearchRequest(results, baseDN,
1422           SearchScope.valueOf(scope), filter, attributes);
1423
1424      searchRequest.setDerefPolicy(
1425           DereferencePolicy.valueOf(c.getDereference()));
1426      searchRequest.setSizeLimit(c.getMaxResults());
1427      searchRequest.setTimeLimitSeconds(c.getServerTimeLimit());
1428      searchRequest.setTypesOnly(typesOnly);
1429
1430      update(searchRequest, constraints);
1431
1432      conn.asyncSearch(searchRequest);
1433      return results;
1434    }
1435    catch (com.unboundid.ldap.sdk.LDAPException le)
1436    {
1437      debugException(le);
1438      setResponseControls(le);
1439      throw new LDAPException(le);
1440    }
1441  }
1442
1443
1444
1445  /**
1446   * Retrieves the set of controls to use in a request.
1447   *
1448   * @param  c  The constraints to be applied.
1449   *
1450   * @return  The set of controls to use in a request.
1451   */
1452  private Control[] getControls(final LDAPConstraints c)
1453  {
1454    Control[] controls = null;
1455    if (c != null)
1456    {
1457      controls = LDAPControl.toControls(c.getServerControls());
1458    }
1459    else if (constraints != null)
1460    {
1461      controls = LDAPControl.toControls(constraints.getServerControls());
1462    }
1463
1464    if (controls == null)
1465    {
1466      return new Control[0];
1467    }
1468    else
1469    {
1470      return controls;
1471    }
1472  }
1473
1474
1475
1476  /**
1477   * Updates the provided request to account for the given set of constraints.
1478   *
1479   * @param  request      The request to be updated.
1480   * @param  constraints  The constraints to be applied.
1481   */
1482  private void update(final UpdatableLDAPRequest request,
1483                      final LDAPConstraints constraints)
1484  {
1485    final LDAPConstraints c =
1486         (constraints == null) ? this.constraints : constraints;
1487
1488    request.setControls(LDAPControl.toControls(c.getServerControls()));
1489    request.setResponseTimeoutMillis(c.getTimeLimit());
1490    request.setFollowReferrals(c.getReferrals());
1491  }
1492
1493
1494
1495  /**
1496   * Sets the response controls for this connection.
1497   *
1498   * @param  ldapResult  The result containing the controls to use.
1499   */
1500  private void setResponseControls(final LDAPResult ldapResult)
1501  {
1502    if (ldapResult.hasResponseControl())
1503    {
1504      responseControls =
1505           LDAPControl.toLDAPControls(ldapResult.getResponseControls());
1506    }
1507    else
1508    {
1509      responseControls = null;
1510    }
1511  }
1512
1513
1514
1515  /**
1516   * Sets the response controls for this connection.
1517   *
1518   * @param  ldapException  The exception containing the controls to use.
1519   */
1520  private void setResponseControls(
1521                    final com.unboundid.ldap.sdk.LDAPException ldapException)
1522  {
1523    if (ldapException.hasResponseControl())
1524    {
1525      responseControls =
1526           LDAPControl.toLDAPControls(ldapException.getResponseControls());
1527    }
1528    else
1529    {
1530      responseControls = null;
1531    }
1532  }
1533}