001/*
002 * Copyright 2009-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-2017 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk;
022
023
024
025import java.io.Closeable;
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.EnumSet;
029import java.util.List;
030import java.util.Set;
031import java.util.concurrent.TimeUnit;
032import java.util.concurrent.TimeoutException;
033
034import com.unboundid.asn1.ASN1OctetString;
035import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
036import com.unboundid.ldap.sdk.schema.Schema;
037import com.unboundid.ldif.LDIFException;
038import com.unboundid.util.NotExtensible;
039import com.unboundid.util.ThreadSafety;
040import com.unboundid.util.ThreadSafetyLevel;
041
042import static com.unboundid.ldap.sdk.LDAPMessages.*;
043import static com.unboundid.util.Debug.*;
044import static com.unboundid.util.StaticUtils.*;
045import static com.unboundid.util.Validator.*;
046
047
048
049/**
050 * This class provides the base class for LDAP connection pool implementations
051 * provided by the LDAP SDK for Java.
052 */
053@NotExtensible()
054@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_NOT_THREADSAFE)
055public abstract class AbstractConnectionPool
056       implements LDAPInterface, Closeable
057{
058  /**
059   * Closes this connection pool.  All connections currently held in the pool
060   * that are not in use will be closed, and any outstanding connections will be
061   * automatically closed when they are released back to the pool.
062   */
063  public abstract void close();
064
065
066
067  /**
068   * Closes this connection pool, optionally using multiple threads to close the
069   * connections in parallel.
070   *
071   * @param  unbind      Indicates whether to try to send an unbind request to
072   *                     the server before closing the connection.
073   * @param  numThreads  The number of threads to use when closing the
074   *                     connections.
075   */
076  public abstract void close(final boolean unbind, final int numThreads);
077
078
079
080  /**
081   * Indicates whether this connection pool has been closed.
082   *
083   * @return  {@code true} if this connection pool has been closed, or
084   *          {@code false} if not.
085   */
086  public abstract boolean isClosed();
087
088
089
090  /**
091   * Retrieves an LDAP connection from the pool.
092   *
093   * @return  The LDAP connection taken from the pool.
094   *
095   * @throws  LDAPException  If no connection is available, or a problem occurs
096   *                         while creating a new connection to return.
097   */
098  public abstract LDAPConnection getConnection()
099         throws LDAPException;
100
101
102
103  /**
104   * Releases the provided connection back to this pool.
105   *
106   * @param  connection  The connection to be released back to the pool.
107   */
108  public abstract void releaseConnection(final LDAPConnection connection);
109
110
111
112  /**
113   * Indicates that the provided connection is no longer in use, but is also no
114   * longer fit for use.  The provided connection will be terminated and a new
115   * connection will be created and added to the pool in its place.
116   *
117   * @param  connection  The defunct connection being released.
118   */
119  public abstract void releaseDefunctConnection(
120                            final LDAPConnection connection);
121
122
123
124  /**
125   * Releases the provided connection back to the pool after an exception has
126   * been encountered while processing an operation on that connection.  The
127   * connection pool health check instance associated with this pool will be
128   * used to determine whether the provided connection is still valid and will
129   * either release it back for use in processing other operations on the
130   * connection or will terminate the connection and create a new one to take
131   * its place.
132   *
133   * @param  connection  The connection to be evaluated and released back to the
134   *                     pool or replaced with a new connection.
135   * @param  exception   The exception caught while processing an operation on
136   *                     the connection.
137   */
138  public final void releaseConnectionAfterException(
139                         final LDAPConnection connection,
140                         final LDAPException exception)
141  {
142    final LDAPConnectionPoolHealthCheck healthCheck = getHealthCheck();
143
144    try
145    {
146      healthCheck.ensureConnectionValidAfterException(connection, exception);
147      releaseConnection(connection);
148    }
149    catch (LDAPException le)
150    {
151      debugException(le);
152      releaseDefunctConnection(connection);
153    }
154  }
155
156
157
158  /**
159   * Releases the provided connection as defunct and creates a new connection to
160   * replace it, if possible, optionally connected to a different directory
161   * server instance than the instance with which the original connection was
162   * established.
163   *
164   * @param  connection  The defunct connection to be replaced.
165   *
166   * @return  The newly-created connection intended to replace the provided
167   *          connection.
168   *
169   * @throws  LDAPException  If a problem is encountered while trying to create
170   *                         the new connection.  Note that even if an exception
171   *                         is thrown, then the provided connection must have
172   *                         been properly released as defunct.
173   */
174  public abstract LDAPConnection replaceDefunctConnection(
175                                      final LDAPConnection connection)
176         throws LDAPException;
177
178
179
180  /**
181   * Attempts to replace the provided connection.  However, if an exception is
182   * encountered while obtaining the new connection then an exception will be
183   * thrown based on the provided {@code Throwable} object.
184   *
185   * @param  t           The {@code Throwable} that was caught and prompted the
186   *                     connection to be replaced.
187   * @param  connection  The defunct connection to be replaced.
188   *
189   * @return  The newly-created connection intended to replace the provided
190   *          connection.
191   *
192   * @throws  LDAPException  If an exception is encountered while attempting to
193   *                         obtain the new connection.  Note that this
194   *                         exception will be generated from the provided
195   *                         {@code Throwable} rather than based on the
196   *                         exception caught while trying to create the new
197   *                         connection.
198   */
199  private LDAPConnection replaceDefunctConnection(final Throwable t,
200                              final LDAPConnection connection)
201          throws LDAPException
202  {
203    try
204    {
205      return replaceDefunctConnection(connection);
206    }
207    catch (final LDAPException le)
208    {
209      debugException(le);
210
211      if (t instanceof LDAPException)
212      {
213        throw (LDAPException) t;
214      }
215      else
216      {
217        throw new LDAPException(ResultCode.LOCAL_ERROR,
218             ERR_POOL_OP_EXCEPTION.get(getExceptionMessage(t)), t);
219      }
220    }
221  }
222
223
224
225  /**
226   * Indicates whether attempts to process operations should be retried on a
227   * newly-created connection if the initial attempt fails in a manner that
228   * indicates that the connection used to process that request may no longer
229   * be valid.  Only a single retry will be attempted for any operation.
230   * <BR><BR>
231   * Note that this only applies to methods used to process operations in the
232   * context pool (e.g., using methods that are part of {@link LDAPInterface}),
233   * and will not automatically be used for operations processed on connections
234   * checked out of the pool.
235   * <BR><BR>
236   * This method is provided for the purpose of backward compatibility, but new
237   * functionality has been added to control retry on a per-operation-type
238   * basis via the {@link #setRetryFailedOperationsDueToInvalidConnections(Set)}
239   * method.  If retry is enabled for any operation type, then this method will
240   * return {@code true}, and it will only return {@code false} if retry should
241   * not be used for any operation type.  To determine the operation types for
242   * which failed operations may be retried, use the
243   * {@link #getOperationTypesToRetryDueToInvalidConnections()}  method.
244   *
245   * @return  {@code true} if the connection pool should attempt to retry
246   *          operations on a newly-created connection if they fail in a way
247   *          that indicates the associated connection may no longer be usable,
248   *          or {@code false} if operations should only be attempted once.
249   */
250  public final boolean retryFailedOperationsDueToInvalidConnections()
251  {
252    return (! getOperationTypesToRetryDueToInvalidConnections().isEmpty());
253  }
254
255
256
257  /**
258   * Retrieves the set of operation types for which operations should be
259   * retried if the initial attempt fails in a manner that indicates that the
260   * connection used to process the request may no longer be valid.
261   *
262   * @return  The set of operation types for which operations should be
263   *          retried if the initial attempt fails in a manner that indicates
264   *          that the connection used to process the request may no longer be
265   *          valid, or an empty set if retries should not be performed for any
266   *          type of operation.
267   */
268  public abstract Set<OperationType>
269              getOperationTypesToRetryDueToInvalidConnections();
270
271
272
273  /**
274   * Specifies whether attempts to process operations should be retried on a
275   * newly-created connection if the initial attempt fails in a manner that
276   * indicates that the connection used to process that request may no longer
277   * be valid.  Only a single retry will be attempted for any operation.
278   * <BR><BR>
279   * Note that this only applies to methods used to process operations in the
280   * context pool (e.g., using methods that are part of {@link LDAPInterface}),
281   * and will not automatically be used for operations processed on connections
282   * checked out of the pool.
283   * <BR><BR>
284   * This method is provided for the purpose of backward compatibility, but new
285   * functionality has been added to control retry on a per-operation-type
286   * basis via the {@link #setRetryFailedOperationsDueToInvalidConnections(Set)}
287   * method.  If this is called with a value of {@code true}, then retry will be
288   * enabled for all types of operations.  If it is called with a value of
289   * {@code false}, then retry will be disabled for all types of operations.
290   *
291   * @param  retryFailedOperationsDueToInvalidConnections
292   *              Indicates whether attempts to process operations should be
293   *              retried on a newly-created connection if they fail in a way
294   *              that indicates the associated connection may no longer be
295   *              usable.
296   */
297  public final void setRetryFailedOperationsDueToInvalidConnections(
298              final boolean retryFailedOperationsDueToInvalidConnections)
299  {
300    if (retryFailedOperationsDueToInvalidConnections)
301    {
302      setRetryFailedOperationsDueToInvalidConnections(
303           EnumSet.allOf(OperationType.class));
304    }
305    else
306    {
307      setRetryFailedOperationsDueToInvalidConnections(
308           EnumSet.noneOf(OperationType.class));
309    }
310  }
311
312
313
314  /**
315   * Specifies the types of operations that should be retried on a newly-created
316   * connection if the initial attempt fails in a manner that indicates that
317   * the connection used to process the request may no longer be valid.  Only a
318   * single retry will be attempted for any operation.
319   * <BR><BR>
320   * Note that this only applies to methods used to process operations in the
321   * context pool (e.g., using methods that are part of {@link LDAPInterface}),
322   * and will not automatically be used for operations processed on connections
323   * checked out of the pool.
324   *
325   * @param  operationTypes  The types of operations for which to retry failed
326   *                         operations if they fail in a way that indicates the
327   *                         associated connection may no longer be usable.  It
328   *                         may be {@code null} or empty to indicate that no
329   *                         types of operations should be retried.
330   */
331  public abstract void setRetryFailedOperationsDueToInvalidConnections(
332              final Set<OperationType> operationTypes);
333
334
335
336  /**
337   * Retrieves the number of connections that are currently available for use in
338   * this connection pool, if applicable.
339   *
340   * @return  The number of connections that are currently available for use in
341   *          this connection pool, or -1 if that is not applicable for this
342   *          type of connection pool.
343   */
344  public abstract int getCurrentAvailableConnections();
345
346
347
348  /**
349   * Retrieves the maximum number of connections to be maintained in this
350   * connection pool, which is the maximum number of available connections that
351   * should be available at any time, if applicable.
352   *
353   * @return  The number of connections to be maintained in this connection
354   *          pool, or -1 if that is not applicable for this type of connection
355   *          pool.
356   */
357  public abstract int getMaximumAvailableConnections();
358
359
360
361  /**
362   * Retrieves the set of statistics maintained for this LDAP connection pool.
363   *
364   * @return  The set of statistics maintained for this LDAP connection pool.
365   */
366  public abstract LDAPConnectionPoolStatistics getConnectionPoolStatistics();
367
368
369
370  /**
371   * Retrieves the user-friendly name that has been assigned to this connection
372   * pool.
373   *
374   * @return  The user-friendly name that has been assigned to this connection
375   *          pool, or {@code null} if none has been assigned.
376   */
377  public abstract String getConnectionPoolName();
378
379
380
381  /**
382   * Specifies the user-friendly name that should be used for this connection
383   * pool.  This name may be used in debugging to help identify the purpose of
384   * this connection pool.  It will also be assigned to all connections
385   * associated with this connection pool.
386   *
387   * @param  connectionPoolName  The user-friendly name that should be used for
388   *                             this connection pool.
389   */
390  public abstract void setConnectionPoolName(final String connectionPoolName);
391
392
393
394  /**
395   * Retrieves the health check implementation for this connection pool.
396   *
397   * @return  The health check implementation for this connection pool.
398   */
399  public abstract LDAPConnectionPoolHealthCheck getHealthCheck();
400
401
402
403  /**
404   * Retrieves the length of time in milliseconds between periodic background
405   * health checks against the available connections in this pool.
406   *
407   * @return  The length of time in milliseconds between the periodic background
408   *          health checks against the available connections in this pool.
409   */
410  public abstract long getHealthCheckIntervalMillis();
411
412
413
414  /**
415   * Specifies the length of time in milliseconds between periodic background
416   * health checks against the available connections in this pool.
417   *
418   * @param  healthCheckInterval  The length of time in milliseconds between
419   *                              periodic background health checks against the
420   *                              available connections in this pool.  The
421   *                              provided value must be greater than zero.
422   */
423  public abstract void setHealthCheckIntervalMillis(
424                            final long healthCheckInterval);
425
426
427
428  /**
429   * Performs a health check against all connections currently available in this
430   * connection pool.  This should only be invoked by the connection pool health
431   * check thread.
432   */
433  protected abstract void doHealthCheck();
434
435
436
437  /**
438   * Retrieves the directory server root DSE using a connection from this
439   * connection pool.
440   *
441   * @return  The directory server root DSE, or {@code null} if it is not
442   *          available.
443   *
444   * @throws  LDAPException  If a problem occurs while attempting to retrieve
445   *                         the server root DSE.
446   */
447  public final RootDSE getRootDSE()
448         throws LDAPException
449  {
450    final LDAPConnection conn = getConnection();
451
452    try
453    {
454      final RootDSE rootDSE = conn.getRootDSE();
455      releaseConnection(conn);
456      return rootDSE;
457    }
458    catch (final Throwable t)
459    {
460      throwLDAPExceptionIfShouldNotRetry(t, OperationType.SEARCH, conn);
461
462      // If we have gotten here, then we should retry the operation with a
463      // newly-created connection.
464      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
465
466      try
467      {
468        final RootDSE rootDSE = newConn.getRootDSE();
469        releaseConnection(newConn);
470        return rootDSE;
471      }
472      catch (final Throwable t2)
473      {
474        throwLDAPException(t2, newConn);
475      }
476
477      // This return statement should never be reached.
478      return null;
479    }
480  }
481
482
483
484  /**
485   * Retrieves the directory server schema definitions using a connection from
486   * this connection pool, using the subschema subentry DN contained in the
487   * server's root DSE.  For directory servers containing a single schema, this
488   * should be sufficient for all purposes.  For servers with multiple schemas,
489   * it may be necessary to specify the DN of the target entry for which to
490   * obtain the associated schema.
491   *
492   * @return  The directory server schema definitions, or {@code null} if the
493   *          schema information could not be retrieved (e.g, the client does
494   *          not have permission to read the server schema).
495   *
496   * @throws  LDAPException  If a problem occurs while attempting to retrieve
497   *                         the server schema.
498   */
499  public final Schema getSchema()
500         throws LDAPException
501  {
502    return getSchema("");
503  }
504
505
506
507  /**
508   * Retrieves the directory server schema definitions that govern the specified
509   * entry using a connection from this connection pool.  The subschemaSubentry
510   * attribute will be retrieved from the target entry, and then the appropriate
511   * schema definitions will be loaded from the entry referenced by that
512   * attribute.  This may be necessary to ensure correct behavior in servers
513   * that support multiple schemas.
514   *
515   * @param  entryDN  The DN of the entry for which to retrieve the associated
516   *                  schema definitions.  It may be {@code null} or an empty
517   *                  string if the subschemaSubentry attribute should be
518   *                  retrieved from the server's root DSE.
519   *
520   * @return  The directory server schema definitions, or {@code null} if the
521   *          schema information could not be retrieved (e.g, the client does
522   *          not have permission to read the server schema).
523   *
524   * @throws  LDAPException  If a problem occurs while attempting to retrieve
525   *                         the server schema.
526   */
527  public final Schema getSchema(final String entryDN)
528         throws LDAPException
529  {
530    final LDAPConnection conn = getConnection();
531
532    try
533    {
534      final Schema schema = conn.getSchema(entryDN);
535      releaseConnection(conn);
536      return schema;
537    }
538    catch (Throwable t)
539    {
540      throwLDAPExceptionIfShouldNotRetry(t, OperationType.SEARCH, conn);
541
542      // If we have gotten here, then we should retry the operation with a
543      // newly-created connection.
544      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
545
546      try
547      {
548        final Schema schema = newConn.getSchema(entryDN);
549        releaseConnection(newConn);
550        return schema;
551      }
552      catch (final Throwable t2)
553      {
554        throwLDAPException(t2, newConn);
555      }
556
557      // This return statement should never be reached.
558      return null;
559    }
560  }
561
562
563
564  /**
565   * Retrieves the entry with the specified DN using a connection from this
566   * connection pool.  All user attributes will be requested in the entry to
567   * return.
568   *
569   * @param  dn  The DN of the entry to retrieve.  It must not be {@code null}.
570   *
571   * @return  The requested entry, or {@code null} if the target entry does not
572   *          exist or no entry was returned (e.g., if the authenticated user
573   *          does not have permission to read the target entry).
574   *
575   * @throws  LDAPException  If a problem occurs while sending the request or
576   *                         reading the response.
577   */
578  public final SearchResultEntry getEntry(final String dn)
579         throws LDAPException
580  {
581    return getEntry(dn, NO_STRINGS);
582  }
583
584
585
586  /**
587   * Retrieves the entry with the specified DN using a connection from this
588   * connection pool.
589   *
590   * @param  dn          The DN of the entry to retrieve.  It must not be
591   *                     {@code null}.
592   * @param  attributes  The set of attributes to request for the target entry.
593   *                     If it is {@code null}, then all user attributes will be
594   *                     requested.
595   *
596   * @return  The requested entry, or {@code null} if the target entry does not
597   *          exist or no entry was returned (e.g., if the authenticated user
598   *          does not have permission to read the target entry).
599   *
600   * @throws  LDAPException  If a problem occurs while sending the request or
601   *                         reading the response.
602   */
603  public final SearchResultEntry getEntry(final String dn,
604                                          final String... attributes)
605         throws LDAPException
606  {
607    final LDAPConnection conn = getConnection();
608
609    try
610    {
611      final SearchResultEntry entry = conn.getEntry(dn, attributes);
612      releaseConnection(conn);
613      return entry;
614    }
615    catch (Throwable t)
616    {
617      throwLDAPExceptionIfShouldNotRetry(t, OperationType.SEARCH, conn);
618
619      // If we have gotten here, then we should retry the operation with a
620      // newly-created connection.
621      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
622
623      try
624      {
625        final SearchResultEntry entry = newConn.getEntry(dn, attributes);
626        releaseConnection(newConn);
627        return entry;
628      }
629      catch (final Throwable t2)
630      {
631        throwLDAPException(t2, newConn);
632      }
633
634      // This return statement should never be reached.
635      return null;
636    }
637  }
638
639
640
641  /**
642   * Processes an add operation with the provided information using a connection
643   * from this connection pool.
644   *
645   * @param  dn          The DN of the entry to add.  It must not be
646   *                     {@code null}.
647   * @param  attributes  The set of attributes to include in the entry to add.
648   *                     It must not be {@code null}.
649   *
650   * @return  The result of processing the add operation.
651   *
652   * @throws  LDAPException  If the server rejects the add request, or if a
653   *                         problem is encountered while sending the request or
654   *                         reading the response.
655   */
656  public final LDAPResult add(final String dn, final Attribute... attributes)
657         throws LDAPException
658  {
659    return add(new AddRequest(dn, attributes));
660  }
661
662
663
664  /**
665   * Processes an add operation with the provided information using a connection
666   * from this connection pool.
667   *
668   * @param  dn          The DN of the entry to add.  It must not be
669   *                     {@code null}.
670   * @param  attributes  The set of attributes to include in the entry to add.
671   *                     It must not be {@code null}.
672   *
673   * @return  The result of processing the add operation.
674   *
675   * @throws  LDAPException  If the server rejects the add request, or if a
676   *                         problem is encountered while sending the request or
677   *                         reading the response.
678   */
679  public final LDAPResult add(final String dn,
680                              final Collection<Attribute> attributes)
681         throws LDAPException
682  {
683    return add(new AddRequest(dn, attributes));
684  }
685
686
687
688  /**
689   * Processes an add operation with the provided information using a connection
690   * from this connection pool.
691   *
692   * @param  entry  The entry to add.  It must not be {@code null}.
693   *
694   * @return  The result of processing the add operation.
695   *
696   * @throws  LDAPException  If the server rejects the add request, or if a
697   *                         problem is encountered while sending the request or
698   *                         reading the response.
699   */
700  public final LDAPResult add(final Entry entry)
701         throws LDAPException
702  {
703    return add(new AddRequest(entry));
704  }
705
706
707
708  /**
709   * Processes an add operation with the provided information using a connection
710   * from this connection pool.
711   *
712   * @param  ldifLines  The lines that comprise an LDIF representation of the
713   *                    entry to add.  It must not be empty or {@code null}.
714   *
715   * @return  The result of processing the add operation.
716   *
717   * @throws  LDIFException  If the provided entry lines cannot be decoded as an
718   *                         entry in LDIF form.
719   *
720   * @throws  LDAPException  If the server rejects the add request, or if a
721   *                         problem is encountered while sending the request or
722   *                         reading the response.
723   */
724  public final LDAPResult add(final String... ldifLines)
725         throws LDIFException, LDAPException
726  {
727    return add(new AddRequest(ldifLines));
728  }
729
730
731
732  /**
733   * Processes the provided add request using a connection from this connection
734   * pool.
735   *
736   * @param  addRequest  The add request to be processed.  It must not be
737   *                     {@code null}.
738   *
739   * @return  The result of processing the add operation.
740   *
741   * @throws  LDAPException  If the server rejects the add request, or if a
742   *                         problem is encountered while sending the request or
743   *                         reading the response.
744   */
745  public final LDAPResult add(final AddRequest addRequest)
746         throws LDAPException
747  {
748    final LDAPConnection conn = getConnection();
749
750    try
751    {
752      final LDAPResult result = conn.add(addRequest);
753      releaseConnection(conn);
754      return result;
755    }
756    catch (Throwable t)
757    {
758      throwLDAPExceptionIfShouldNotRetry(t, OperationType.ADD, conn);
759
760      // If we have gotten here, then we should retry the operation with a
761      // newly-created connection.
762      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
763
764      try
765      {
766        final LDAPResult result = newConn.add(addRequest);
767        releaseConnection(newConn);
768        return result;
769      }
770      catch (final Throwable t2)
771      {
772        throwLDAPException(t2, newConn);
773      }
774
775      // This return statement should never be reached.
776      return null;
777    }
778  }
779
780
781
782  /**
783   * Processes the provided add request using a connection from this connection
784   * pool.
785   *
786   * @param  addRequest  The add request to be processed.  It must not be
787   *                     {@code null}.
788   *
789   * @return  The result of processing the add operation.
790   *
791   * @throws  LDAPException  If the server rejects the add request, or if a
792   *                         problem is encountered while sending the request or
793   *                         reading the response.
794   */
795  public final LDAPResult add(final ReadOnlyAddRequest addRequest)
796         throws LDAPException
797  {
798    return add((AddRequest) addRequest);
799  }
800
801
802
803  /**
804   * Processes a simple bind request with the provided DN and password using a
805   * connection from this connection pool.  Note that this will impact the state
806   * of the connection in the pool, and therefore this method should only be
807   * used if this connection pool is used exclusively for processing bind
808   * operations, or if the retain identity request control (only available in
809   * the Commercial Edition of the LDAP SDK for use with the Ping Identity,
810   * UnboundID, or Alcatel-Lucent 8661 Directory Server) is included in the bind
811   * request to ensure that the authentication state is not impacted.
812   *
813   * @param  bindDN    The bind DN for the bind operation.
814   * @param  password  The password for the simple bind operation.
815   *
816   * @return  The result of processing the bind operation.
817   *
818   * @throws  LDAPException  If the server rejects the bind request, or if a
819   *                         problem occurs while sending the request or reading
820   *                         the response.
821   */
822  public final BindResult bind(final String bindDN, final String password)
823         throws LDAPException
824  {
825    return bind(new SimpleBindRequest(bindDN, password));
826  }
827
828
829
830  /**
831   * Processes the provided bind request using a connection from this connection
832   * pool.  Note that this will impact the state of the connection in the pool,
833   * and therefore this method should only be used if this connection pool is
834   * used exclusively for processing bind operations, or if the retain identity
835   * request control (only available in the Commercial Edition of the LDAP SDK
836   * for use with the Ping Identity, UnboundID, or Alcatel-Lucent 8661 Directory
837   * Server) is included in the bind request to ensure that the authentication
838   * state is not impacted.
839   *
840   * @param  bindRequest  The bind request to be processed.  It must not be
841   *                      {@code null}.
842   *
843   * @return  The result of processing the bind operation.
844   *
845   * @throws  LDAPException  If the server rejects the bind request, or if a
846   *                         problem occurs while sending the request or reading
847   *                         the response.
848   */
849  public final BindResult bind(final BindRequest bindRequest)
850         throws LDAPException
851  {
852    final LDAPConnection conn = getConnection();
853
854    try
855    {
856      final BindResult result = conn.bind(bindRequest);
857      releaseConnection(conn);
858      return result;
859    }
860    catch (Throwable t)
861    {
862      throwLDAPExceptionIfShouldNotRetry(t, OperationType.BIND, conn);
863
864      // If we have gotten here, then we should retry the operation with a
865      // newly-created connection.
866      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
867
868      try
869      {
870        final BindResult result = newConn.bind(bindRequest);
871        releaseConnection(newConn);
872        return result;
873      }
874      catch (final Throwable t2)
875      {
876        throwLDAPException(t2, newConn);
877      }
878
879      // This return statement should never be reached.
880      return null;
881    }
882  }
883
884
885
886  /**
887   * Processes a compare operation with the provided information using a
888   * connection from this connection pool.
889   *
890   * @param  dn              The DN of the entry in which to make the
891   *                         comparison.  It must not be {@code null}.
892   * @param  attributeName   The attribute name for which to make the
893   *                         comparison.  It must not be {@code null}.
894   * @param  assertionValue  The assertion value to verify in the target entry.
895   *                         It must not be {@code null}.
896   *
897   * @return  The result of processing the compare operation.
898   *
899   * @throws  LDAPException  If the server rejects the compare request, or if a
900   *                         problem is encountered while sending the request or
901   *                         reading the response.
902   */
903  public final CompareResult compare(final String dn,
904                                     final String attributeName,
905                                     final String assertionValue)
906         throws LDAPException
907  {
908    return compare(new CompareRequest(dn, attributeName, assertionValue));
909  }
910
911
912
913  /**
914   * Processes the provided compare request using a connection from this
915   * connection pool.
916   *
917   * @param  compareRequest  The compare request to be processed.  It must not
918   *                         be {@code null}.
919   *
920   * @return  The result of processing the compare operation.
921   *
922   * @throws  LDAPException  If the server rejects the compare request, or if a
923   *                         problem is encountered while sending the request or
924   *                         reading the response.
925   */
926  public final CompareResult compare(final CompareRequest compareRequest)
927         throws LDAPException
928  {
929    final LDAPConnection conn = getConnection();
930
931    try
932    {
933      final CompareResult result = conn.compare(compareRequest);
934      releaseConnection(conn);
935      return result;
936    }
937    catch (Throwable t)
938    {
939      throwLDAPExceptionIfShouldNotRetry(t, OperationType.COMPARE, conn);
940
941      // If we have gotten here, then we should retry the operation with a
942      // newly-created connection.
943      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
944
945      try
946      {
947        final CompareResult result = newConn.compare(compareRequest);
948        releaseConnection(newConn);
949        return result;
950      }
951      catch (final Throwable t2)
952      {
953        throwLDAPException(t2, newConn);
954      }
955
956      // This return statement should never be reached.
957      return null;
958    }
959  }
960
961
962
963  /**
964   * Processes the provided compare request using a connection from this
965   * connection pool.
966   *
967   * @param  compareRequest  The compare request to be processed.  It must not
968   *                         be {@code null}.
969   *
970   * @return  The result of processing the compare operation.
971   *
972   * @throws  LDAPException  If the server rejects the compare request, or if a
973   *                         problem is encountered while sending the request or
974   *                         reading the response.
975   */
976  public final CompareResult compare(
977                                  final ReadOnlyCompareRequest compareRequest)
978         throws LDAPException
979  {
980    return compare((CompareRequest) compareRequest);
981  }
982
983
984
985  /**
986   * Deletes the entry with the specified DN using a connection from this
987   * connection pool.
988   *
989   * @param  dn  The DN of the entry to delete.  It must not be {@code null}.
990   *
991   * @return  The result of processing the delete operation.
992   *
993   * @throws  LDAPException  If the server rejects the delete request, or if a
994   *                         problem is encountered while sending the request or
995   *                         reading the response.
996   */
997  public final LDAPResult delete(final String dn)
998         throws LDAPException
999  {
1000    return delete(new DeleteRequest(dn));
1001  }
1002
1003
1004
1005  /**
1006   * Processes the provided delete request using a connection from this
1007   * connection pool.
1008   *
1009   * @param  deleteRequest  The delete request to be processed.  It must not be
1010   *                        {@code null}.
1011   *
1012   * @return  The result of processing the delete operation.
1013   *
1014   * @throws  LDAPException  If the server rejects the delete request, or if a
1015   *                         problem is encountered while sending the request or
1016   *                         reading the response.
1017   */
1018  public final LDAPResult delete(final DeleteRequest deleteRequest)
1019         throws LDAPException
1020  {
1021    final LDAPConnection conn = getConnection();
1022
1023    try
1024    {
1025      final LDAPResult result = conn.delete(deleteRequest);
1026      releaseConnection(conn);
1027      return result;
1028    }
1029    catch (Throwable t)
1030    {
1031      throwLDAPExceptionIfShouldNotRetry(t, OperationType.DELETE, conn);
1032
1033      // If we have gotten here, then we should retry the operation with a
1034      // newly-created connection.
1035      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
1036
1037      try
1038      {
1039        final LDAPResult result = newConn.delete(deleteRequest);
1040        releaseConnection(newConn);
1041        return result;
1042      }
1043      catch (final Throwable t2)
1044      {
1045        throwLDAPException(t2, newConn);
1046      }
1047
1048      // This return statement should never be reached.
1049      return null;
1050    }
1051  }
1052
1053
1054
1055  /**
1056   * Processes the provided delete request using a connection from this
1057   * connection pool.
1058   *
1059   * @param  deleteRequest  The delete request to be processed.  It must not be
1060   *                        {@code null}.
1061   *
1062   * @return  The result of processing the delete operation.
1063   *
1064   * @throws  LDAPException  If the server rejects the delete request, or if a
1065   *                         problem is encountered while sending the request or
1066   *                         reading the response.
1067   */
1068  public final LDAPResult delete(final ReadOnlyDeleteRequest deleteRequest)
1069         throws LDAPException
1070  {
1071    return delete((DeleteRequest) deleteRequest);
1072  }
1073
1074
1075
1076  /**
1077   * Processes an extended operation with the provided request OID using a
1078   * connection from this connection pool.  Note that this method should not be
1079   * used to perform any operation that will alter the state of the connection
1080   * in the pool (e.g., a StartTLS operation) or that involves multiple
1081   * distinct operations on the same connection (e.g., LDAP transactions).
1082   *
1083   * @param  requestOID  The OID for the extended request to process.  It must
1084   *                     not be {@code null}.
1085   *
1086   * @return  The extended result object that provides information about the
1087   *          result of the request processing.
1088   *
1089   * @throws  LDAPException  If a problem occurs while sending the request or
1090   *                         reading the response.
1091   */
1092  public final ExtendedResult processExtendedOperation(final String requestOID)
1093         throws LDAPException
1094  {
1095    return processExtendedOperation(new ExtendedRequest(requestOID));
1096  }
1097
1098
1099
1100  /**
1101   * Processes an extended operation with the provided request OID and value
1102   * using a connection from this connection pool.  Note that this method should
1103   * not be used to perform any operation that will alter the state of the
1104   * connection in the pool (e.g., a StartTLS operation) or that involves
1105   * multiple distinct operations on the same connection (e.g., LDAP
1106   * transactions).
1107   *
1108   * @param  requestOID    The OID for the extended request to process.  It must
1109   *                       not be {@code null}.
1110   * @param  requestValue  The encoded value for the extended request to
1111   *                       process.  It may be {@code null} if there does not
1112   *                       need to be a value for the requested operation.
1113   *
1114   * @return  The extended result object that provides information about the
1115   *          result of the request processing.
1116   *
1117   * @throws  LDAPException  If a problem occurs while sending the request or
1118   *                         reading the response.
1119   */
1120  public final ExtendedResult processExtendedOperation(final String requestOID,
1121                                   final ASN1OctetString requestValue)
1122         throws LDAPException
1123  {
1124    return processExtendedOperation(new ExtendedRequest(requestOID,
1125         requestValue));
1126  }
1127
1128
1129
1130  /**
1131   * Processes the provided extended request using a connection from this
1132   * connection pool.  Note that this method should not be used to perform any
1133   * operation that will alter the state of the connection in the pool (e.g., a
1134   * StartTLS operation) or that involves multiple distinct operations on the
1135   * same connection (e.g., LDAP transactions).
1136   *
1137   * @param  extendedRequest  The extended request to be processed.  It must not
1138   *                          be {@code null}.
1139   *
1140   * @return  The extended result object that provides information about the
1141   *          result of the request processing.
1142   *
1143   * @throws  LDAPException  If a problem occurs while sending the request or
1144   *                         reading the response.
1145   */
1146  public final ExtendedResult processExtendedOperation(
1147                                   final ExtendedRequest extendedRequest)
1148         throws LDAPException
1149  {
1150    if (extendedRequest.getOID().equals(
1151         StartTLSExtendedRequest.STARTTLS_REQUEST_OID))
1152    {
1153      throw new LDAPException(ResultCode.NOT_SUPPORTED,
1154                              ERR_POOL_STARTTLS_NOT_ALLOWED.get());
1155    }
1156
1157    final LDAPConnection conn = getConnection();
1158
1159    try
1160    {
1161      final ExtendedResult result =
1162           conn.processExtendedOperation(extendedRequest);
1163      releaseConnection(conn);
1164      return result;
1165    }
1166    catch (Throwable t)
1167    {
1168      throwLDAPExceptionIfShouldNotRetry(t, OperationType.EXTENDED, conn);
1169
1170      // If we have gotten here, then we should retry the operation with a
1171      // newly-created connection.
1172      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
1173
1174      try
1175      {
1176        final ExtendedResult result =
1177             newConn.processExtendedOperation(extendedRequest);
1178        releaseConnection(newConn);
1179        return result;
1180      }
1181      catch (final Throwable t2)
1182      {
1183        throwLDAPException(t2, newConn);
1184      }
1185
1186      // This return statement should never be reached.
1187      return null;
1188    }
1189  }
1190
1191
1192
1193  /**
1194   * Applies the provided modification to the specified entry using a connection
1195   * from this connection pool.
1196   *
1197   * @param  dn   The DN of the entry to modify.  It must not be {@code null}.
1198   * @param  mod  The modification to apply to the target entry.  It must not
1199   *              be {@code null}.
1200   *
1201   * @return  The result of processing the modify operation.
1202   *
1203   * @throws  LDAPException  If the server rejects the modify request, or if a
1204   *                         problem is encountered while sending the request or
1205   *                         reading the response.
1206   */
1207  public final LDAPResult modify(final String dn, final Modification mod)
1208         throws LDAPException
1209  {
1210    return modify(new ModifyRequest(dn, mod));
1211  }
1212
1213
1214
1215  /**
1216   * Applies the provided set of modifications to the specified entry using a
1217   * connection from this connection pool.
1218   *
1219   * @param  dn    The DN of the entry to modify.  It must not be {@code null}.
1220   * @param  mods  The set of modifications to apply to the target entry.  It
1221   *               must not be {@code null} or empty.  *
1222   * @return  The result of processing the modify operation.
1223   *
1224   * @throws  LDAPException  If the server rejects the modify request, or if a
1225   *                         problem is encountered while sending the request or
1226   *                         reading the response.
1227   */
1228  public final LDAPResult modify(final String dn, final Modification... mods)
1229         throws LDAPException
1230  {
1231    return modify(new ModifyRequest(dn, mods));
1232  }
1233
1234
1235
1236  /**
1237   * Applies the provided set of modifications to the specified entry using a
1238   * connection from this connection pool.
1239   *
1240   * @param  dn    The DN of the entry to modify.  It must not be {@code null}.
1241   * @param  mods  The set of modifications to apply to the target entry.  It
1242   *               must not be {@code null} or empty.
1243   *
1244   * @return  The result of processing the modify operation.
1245   *
1246   * @throws  LDAPException  If the server rejects the modify request, or if a
1247   *                         problem is encountered while sending the request or
1248   *                         reading the response.
1249   */
1250  public final LDAPResult modify(final String dn, final List<Modification> mods)
1251         throws LDAPException
1252  {
1253    return modify(new ModifyRequest(dn, mods));
1254  }
1255
1256
1257
1258  /**
1259   * Processes a modify request from the provided LDIF representation of the
1260   * changes using a connection from this connection pool.
1261   *
1262   * @param  ldifModificationLines  The lines that comprise an LDIF
1263   *                                representation of a modify change record.
1264   *                                It must not be {@code null} or empty.
1265   *
1266   * @return  The result of processing the modify operation.
1267   *
1268   * @throws  LDIFException  If the provided set of lines cannot be parsed as an
1269   *                         LDIF modify change record.
1270   *
1271   * @throws  LDAPException  If the server rejects the modify request, or if a
1272   *                         problem is encountered while sending the request or
1273   *                         reading the response.
1274   *
1275   */
1276  public final LDAPResult modify(final String... ldifModificationLines)
1277         throws LDIFException, LDAPException
1278  {
1279    return modify(new ModifyRequest(ldifModificationLines));
1280  }
1281
1282
1283
1284  /**
1285   * Processes the provided modify request using a connection from this
1286   * connection pool.
1287   *
1288   * @param  modifyRequest  The modify request to be processed.  It must not be
1289   *                        {@code null}.
1290   *
1291   * @return  The result of processing the modify operation.
1292   *
1293   * @throws  LDAPException  If the server rejects the modify request, or if a
1294   *                         problem is encountered while sending the request or
1295   *                         reading the response.
1296   */
1297  public final LDAPResult modify(final ModifyRequest modifyRequest)
1298         throws LDAPException
1299  {
1300    final LDAPConnection conn = getConnection();
1301
1302    try
1303    {
1304      final LDAPResult result = conn.modify(modifyRequest);
1305      releaseConnection(conn);
1306      return result;
1307    }
1308    catch (Throwable t)
1309    {
1310      throwLDAPExceptionIfShouldNotRetry(t, OperationType.MODIFY, conn);
1311
1312      // If we have gotten here, then we should retry the operation with a
1313      // newly-created connection.
1314      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
1315
1316      try
1317      {
1318        final LDAPResult result = newConn.modify(modifyRequest);
1319        releaseConnection(newConn);
1320        return result;
1321      }
1322      catch (final Throwable t2)
1323      {
1324        throwLDAPException(t2, newConn);
1325      }
1326
1327      // This return statement should never be reached.
1328      return null;
1329    }
1330  }
1331
1332
1333
1334  /**
1335   * Processes the provided modify request using a connection from this
1336   * connection pool.
1337   *
1338   * @param  modifyRequest  The modify request to be processed.  It must not be
1339   *                        {@code null}.
1340   *
1341   * @return  The result of processing the modify operation.
1342   *
1343   * @throws  LDAPException  If the server rejects the modify request, or if a
1344   *                         problem is encountered while sending the request or
1345   *                         reading the response.
1346   */
1347  public final LDAPResult modify(final ReadOnlyModifyRequest modifyRequest)
1348         throws LDAPException
1349  {
1350    return modify((ModifyRequest) modifyRequest);
1351  }
1352
1353
1354
1355  /**
1356   * Performs a modify DN operation with the provided information using a
1357   * connection from this connection pool.
1358   *
1359   * @param  dn            The current DN for the entry to rename.  It must not
1360   *                       be {@code null}.
1361   * @param  newRDN        The new RDN to use for the entry.  It must not be
1362   *                       {@code null}.
1363   * @param  deleteOldRDN  Indicates whether to delete the current RDN value
1364   *                       from the entry.
1365   *
1366   * @return  The result of processing the modify DN operation.
1367   *
1368   * @throws  LDAPException  If the server rejects the modify DN request, or if
1369   *                         a problem is encountered while sending the request
1370   *                         or reading the response.
1371   */
1372  public final LDAPResult modifyDN(final String dn, final String newRDN,
1373                                   final boolean deleteOldRDN)
1374         throws LDAPException
1375  {
1376    return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN));
1377  }
1378
1379
1380
1381  /**
1382   * Performs a modify DN operation with the provided information using a
1383   * connection from this connection pool.
1384   *
1385   * @param  dn             The current DN for the entry to rename.  It must not
1386   *                        be {@code null}.
1387   * @param  newRDN         The new RDN to use for the entry.  It must not be
1388   *                        {@code null}.
1389   * @param  deleteOldRDN   Indicates whether to delete the current RDN value
1390   *                        from the entry.
1391   * @param  newSuperiorDN  The new superior DN for the entry.  It may be
1392   *                        {@code null} if the entry is not to be moved below a
1393   *                        new parent.
1394   *
1395   * @return  The result of processing the modify DN operation.
1396   *
1397   * @throws  LDAPException  If the server rejects the modify DN request, or if
1398   *                         a problem is encountered while sending the request
1399   *                         or reading the response.
1400   */
1401  public final LDAPResult modifyDN(final String dn, final String newRDN,
1402                                   final boolean deleteOldRDN,
1403                                   final String newSuperiorDN)
1404         throws LDAPException
1405  {
1406    return modifyDN(new ModifyDNRequest(dn, newRDN, deleteOldRDN,
1407         newSuperiorDN));
1408  }
1409
1410
1411
1412  /**
1413   * Processes the provided modify DN request using a connection from this
1414   * connection pool.
1415   *
1416   * @param  modifyDNRequest  The modify DN request to be processed.  It must
1417   *                          not be {@code null}.
1418   *
1419   * @return  The result of processing the modify DN operation.
1420   *
1421   * @throws  LDAPException  If the server rejects the modify DN request, or if
1422   *                         a problem is encountered while sending the request
1423   *                         or reading the response.
1424   */
1425  public final LDAPResult modifyDN(final ModifyDNRequest modifyDNRequest)
1426         throws LDAPException
1427  {
1428    final LDAPConnection conn = getConnection();
1429
1430    try
1431    {
1432      final LDAPResult result = conn.modifyDN(modifyDNRequest);
1433      releaseConnection(conn);
1434      return result;
1435    }
1436    catch (Throwable t)
1437    {
1438      throwLDAPExceptionIfShouldNotRetry(t, OperationType.MODIFY_DN, conn);
1439
1440      // If we have gotten here, then we should retry the operation with a
1441      // newly-created connection.
1442      final LDAPConnection newConn = replaceDefunctConnection(t, conn);
1443
1444      try
1445      {
1446        final LDAPResult result = newConn.modifyDN(modifyDNRequest);
1447        releaseConnection(newConn);
1448        return result;
1449      }
1450      catch (final Throwable t2)
1451      {
1452        throwLDAPException(t2, newConn);
1453      }
1454
1455      // This return statement should never be reached.
1456      return null;
1457    }
1458  }
1459
1460
1461
1462  /**
1463   * Processes the provided modify DN request using a connection from this
1464   * connection pool.
1465   *
1466   * @param  modifyDNRequest  The modify DN request to be processed.  It must
1467   *                          not be {@code null}.
1468   *
1469   * @return  The result of processing the modify DN operation.
1470   *
1471   * @throws  LDAPException  If the server rejects the modify DN request, or if
1472   *                         a problem is encountered while sending the request
1473   *                         or reading the response.
1474   */
1475  public final LDAPResult modifyDN(
1476                               final ReadOnlyModifyDNRequest modifyDNRequest)
1477         throws LDAPException
1478  {
1479    return modifyDN((ModifyDNRequest) modifyDNRequest);
1480  }
1481
1482
1483
1484  /**
1485   * Processes a search operation with the provided information using a
1486   * connection from this connection pool.  The search result entries and
1487   * references will be collected internally and included in the
1488   * {@code SearchResult} object that is returned.
1489   * <BR><BR>
1490   * Note that if the search does not complete successfully, an
1491   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1492   * search result entries or references may have been returned before the
1493   * failure response is received.  In this case, the
1494   * {@code LDAPSearchException} methods like {@code getEntryCount},
1495   * {@code getSearchEntries}, {@code getReferenceCount}, and
1496   * {@code getSearchReferences} may be used to obtain information about those
1497   * entries and references.
1498   *
1499   * @param  baseDN      The base DN for the search request.  It must not be
1500   *                     {@code null}.
1501   * @param  scope       The scope that specifies the range of entries that
1502   *                     should be examined for the search.
1503   * @param  filter      The string representation of the filter to use to
1504   *                     identify matching entries.  It must not be
1505   *                     {@code null}.
1506   * @param  attributes  The set of attributes that should be returned in
1507   *                     matching entries.  It may be {@code null} or empty if
1508   *                     the default attribute set (all user attributes) is to
1509   *                     be requested.
1510   *
1511   * @return  A search result object that provides information about the
1512   *          processing of the search, including the set of matching entries
1513   *          and search references returned by the server.
1514   *
1515   * @throws  LDAPSearchException  If the search does not complete successfully,
1516   *                               or if a problem is encountered while parsing
1517   *                               the provided filter string, sending the
1518   *                               request, or reading the response.  If one or
1519   *                               more entries or references were returned
1520   *                               before the failure was encountered, then the
1521   *                               {@code LDAPSearchException} object may be
1522   *                               examined to obtain information about those
1523   *                               entries and/or references.
1524   */
1525  public final SearchResult search(final String baseDN, final SearchScope scope,
1526                                   final String filter,
1527                                   final String... attributes)
1528         throws LDAPSearchException
1529  {
1530    return search(new SearchRequest(baseDN, scope, parseFilter(filter),
1531         attributes));
1532  }
1533
1534
1535
1536  /**
1537   * Processes a search operation with the provided information using a
1538   * connection from this connection pool.  The search result entries and
1539   * references will be collected internally and included in the
1540   * {@code SearchResult} object that is returned.
1541   * <BR><BR>
1542   * Note that if the search does not complete successfully, an
1543   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1544   * search result entries or references may have been returned before the
1545   * failure response is received.  In this case, the
1546   * {@code LDAPSearchException} methods like {@code getEntryCount},
1547   * {@code getSearchEntries}, {@code getReferenceCount}, and
1548   * {@code getSearchReferences} may be used to obtain information about those
1549   * entries and references.
1550   *
1551   * @param  baseDN      The base DN for the search request.  It must not be
1552   *                     {@code null}.
1553   * @param  scope       The scope that specifies the range of entries that
1554   *                     should be examined for the search.
1555   * @param  filter      The filter to use to identify matching entries.  It
1556   *                     must not be {@code null}.
1557   * @param  attributes  The set of attributes that should be returned in
1558   *                     matching entries.  It may be {@code null} or empty if
1559   *                     the default attribute set (all user attributes) is to
1560   *                     be requested.
1561   *
1562   * @return  A search result object that provides information about the
1563   *          processing of the search, including the set of matching entries
1564   *          and search references returned by the server.
1565   *
1566   * @throws  LDAPSearchException  If the search does not complete successfully,
1567   *                               or if a problem is encountered while sending
1568   *                               the request or reading the response.  If one
1569   *                               or more entries or references were returned
1570   *                               before the failure was encountered, then the
1571   *                               {@code LDAPSearchException} object may be
1572   *                               examined to obtain information about those
1573   *                               entries and/or references.
1574   */
1575  public final SearchResult search(final String baseDN, final SearchScope scope,
1576                                   final Filter filter,
1577                                   final String... attributes)
1578         throws LDAPSearchException
1579  {
1580    return search(new SearchRequest(baseDN, scope, filter, attributes));
1581  }
1582
1583
1584
1585  /**
1586   * Processes a search operation with the provided information using a
1587   * connection from this connection pool.
1588   * <BR><BR>
1589   * Note that if the search does not complete successfully, an
1590   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1591   * search result entries or references may have been returned before the
1592   * failure response is received.  In this case, the
1593   * {@code LDAPSearchException} methods like {@code getEntryCount},
1594   * {@code getSearchEntries}, {@code getReferenceCount}, and
1595   * {@code getSearchReferences} may be used to obtain information about those
1596   * entries and references (although if a search result listener was provided,
1597   * then it will have been used to make any entries and references available,
1598   * and they will not be available through the {@code getSearchEntries} and
1599   * {@code getSearchReferences} methods).
1600   *
1601   * @param  searchResultListener  The search result listener that should be
1602   *                               used to return results to the client.  It may
1603   *                               be {@code null} if the search results should
1604   *                               be collected internally and returned in the
1605   *                               {@code SearchResult} object.
1606   * @param  baseDN                The base DN for the search request.  It must
1607   *                               not be {@code null}.
1608   * @param  scope                 The scope that specifies the range of entries
1609   *                               that should be examined for the search.
1610   * @param  filter                The string representation of the filter to
1611   *                               use to identify matching entries.  It must
1612   *                               not be {@code null}.
1613   * @param  attributes            The set of attributes that should be returned
1614   *                               in matching entries.  It may be {@code null}
1615   *                               or empty if the default attribute set (all
1616   *                               user attributes) is to be requested.
1617   *
1618   * @return  A search result object that provides information about the
1619   *          processing of the search, potentially including the set of
1620   *          matching entries and search references returned by the server.
1621   *
1622   * @throws  LDAPSearchException  If the search does not complete successfully,
1623   *                               or if a problem is encountered while parsing
1624   *                               the provided filter string, sending the
1625   *                               request, or reading the response.  If one
1626   *                               or more entries or references were returned
1627   *                               before the failure was encountered, then the
1628   *                               {@code LDAPSearchException} object may be
1629   *                               examined to obtain information about those
1630   *                               entries and/or references.
1631   */
1632  public final SearchResult
1633       search(final SearchResultListener searchResultListener,
1634              final String baseDN, final SearchScope scope, final String filter,
1635              final String... attributes)
1636         throws LDAPSearchException
1637  {
1638    return search(new SearchRequest(searchResultListener, baseDN, scope,
1639         parseFilter(filter), attributes));
1640  }
1641
1642
1643
1644  /**
1645   * Processes a search operation with the provided information using a
1646   * connection from this connection pool.
1647   * <BR><BR>
1648   * Note that if the search does not complete successfully, an
1649   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1650   * search result entries or references may have been returned before the
1651   * failure response is received.  In this case, the
1652   * {@code LDAPSearchException} methods like {@code getEntryCount},
1653   * {@code getSearchEntries}, {@code getReferenceCount}, and
1654   * {@code getSearchReferences} may be used to obtain information about those
1655   * entries and references (although if a search result listener was provided,
1656   * then it will have been used to make any entries and references available,
1657   * and they will not be available through the {@code getSearchEntries} and
1658   * {@code getSearchReferences} methods).
1659   *
1660   * @param  searchResultListener  The search result listener that should be
1661   *                               used to return results to the client.  It may
1662   *                               be {@code null} if the search results should
1663   *                               be collected internally and returned in the
1664   *                               {@code SearchResult} object.
1665   * @param  baseDN                The base DN for the search request.  It must
1666   *                               not be {@code null}.
1667   * @param  scope                 The scope that specifies the range of entries
1668   *                               that should be examined for the search.
1669   * @param  filter                The filter to use to identify matching
1670   *                               entries.  It must not be {@code null}.
1671   * @param  attributes            The set of attributes that should be returned
1672   *                               in matching entries.  It may be {@code null}
1673   *                               or empty if the default attribute set (all
1674   *                               user attributes) is to be requested.
1675   *
1676   * @return  A search result object that provides information about the
1677   *          processing of the search, potentially including the set of
1678   *          matching entries and search references returned by the server.
1679   *
1680   * @throws  LDAPSearchException  If the search does not complete successfully,
1681   *                               or if a problem is encountered while sending
1682   *                               the request or reading the response.  If one
1683   *                               or more entries or references were returned
1684   *                               before the failure was encountered, then the
1685   *                               {@code LDAPSearchException} object may be
1686   *                               examined to obtain information about those
1687   *                               entries and/or references.
1688   */
1689  public final SearchResult
1690       search(final SearchResultListener searchResultListener,
1691              final String baseDN, final SearchScope scope, final Filter filter,
1692              final String... attributes)
1693         throws LDAPSearchException
1694  {
1695    return search(new SearchRequest(searchResultListener, baseDN, scope,
1696         filter, attributes));
1697  }
1698
1699
1700
1701  /**
1702   * Processes a search operation with the provided information using a
1703   * connection from this connection pool.  The search result entries and
1704   * references will be collected internally and included in the
1705   * {@code SearchResult} object that is returned.
1706   * <BR><BR>
1707   * Note that if the search does not complete successfully, an
1708   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1709   * search result entries or references may have been returned before the
1710   * failure response is received.  In this case, the
1711   * {@code LDAPSearchException} methods like {@code getEntryCount},
1712   * {@code getSearchEntries}, {@code getReferenceCount}, and
1713   * {@code getSearchReferences} may be used to obtain information about those
1714   * entries and references.
1715   *
1716   * @param  baseDN       The base DN for the search request.  It must not be
1717   *                      {@code null}.
1718   * @param  scope        The scope that specifies the range of entries that
1719   *                      should be examined for the search.
1720   * @param  derefPolicy  The dereference policy the server should use for any
1721   *                      aliases encountered while processing the search.
1722   * @param  sizeLimit    The maximum number of entries that the server should
1723   *                      return for the search.  A value of zero indicates that
1724   *                      there should be no limit.
1725   * @param  timeLimit    The maximum length of time in seconds that the server
1726   *                      should spend processing this search request.  A value
1727   *                      of zero indicates that there should be no limit.
1728   * @param  typesOnly    Indicates whether to return only attribute names in
1729   *                      matching entries, or both attribute names and values.
1730   * @param  filter       The string representation of the filter to use to
1731   *                      identify matching entries.  It must not be
1732   *                      {@code null}.
1733   * @param  attributes   The set of attributes that should be returned in
1734   *                      matching entries.  It may be {@code null} or empty if
1735   *                      the default attribute set (all user attributes) is to
1736   *                      be requested.
1737   *
1738   * @return  A search result object that provides information about the
1739   *          processing of the search, including the set of matching entries
1740   *          and search references returned by the server.
1741   *
1742   * @throws  LDAPSearchException  If the search does not complete successfully,
1743   *                               or if a problem is encountered while parsing
1744   *                               the provided filter string, sending the
1745   *                               request, or reading the response.  If one
1746   *                               or more entries or references were returned
1747   *                               before the failure was encountered, then the
1748   *                               {@code LDAPSearchException} object may be
1749   *                               examined to obtain information about those
1750   *                               entries and/or references.
1751   */
1752  public final SearchResult search(final String baseDN, final SearchScope scope,
1753                                   final DereferencePolicy derefPolicy,
1754                                   final int sizeLimit, final int timeLimit,
1755                                   final boolean typesOnly, final String filter,
1756                                   final String... attributes)
1757         throws LDAPSearchException
1758  {
1759    return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
1760         timeLimit, typesOnly, parseFilter(filter), attributes));
1761  }
1762
1763
1764
1765  /**
1766   * Processes a search operation with the provided information using a
1767   * connection from this connection pool.  The search result entries and
1768   * references will be collected internally and included in the
1769   * {@code SearchResult} object that is returned.
1770   * <BR><BR>
1771   * Note that if the search does not complete successfully, an
1772   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1773   * search result entries or references may have been returned before the
1774   * failure response is received.  In this case, the
1775   * {@code LDAPSearchException} methods like {@code getEntryCount},
1776   * {@code getSearchEntries}, {@code getReferenceCount}, and
1777   * {@code getSearchReferences} may be used to obtain information about those
1778   * entries and references.
1779   *
1780   * @param  baseDN       The base DN for the search request.  It must not be
1781   *                      {@code null}.
1782   * @param  scope        The scope that specifies the range of entries that
1783   *                      should be examined for the search.
1784   * @param  derefPolicy  The dereference policy the server should use for any
1785   *                      aliases encountered while processing the search.
1786   * @param  sizeLimit    The maximum number of entries that the server should
1787   *                      return for the search.  A value of zero indicates that
1788   *                      there should be no limit.
1789   * @param  timeLimit    The maximum length of time in seconds that the server
1790   *                      should spend processing this search request.  A value
1791   *                      of zero indicates that there should be no limit.
1792   * @param  typesOnly    Indicates whether to return only attribute names in
1793   *                      matching entries, or both attribute names and values.
1794   * @param  filter       The filter to use to identify matching entries.  It
1795   *                      must not be {@code null}.
1796   * @param  attributes   The set of attributes that should be returned in
1797   *                      matching entries.  It may be {@code null} or empty if
1798   *                      the default attribute set (all user attributes) is to
1799   *                      be requested.
1800   *
1801   * @return  A search result object that provides information about the
1802   *          processing of the search, including the set of matching entries
1803   *          and search references returned by the server.
1804   *
1805   * @throws  LDAPSearchException  If the search does not complete successfully,
1806   *                               or if a problem is encountered while sending
1807   *                               the request or reading the response.  If one
1808   *                               or more entries or references were returned
1809   *                               before the failure was encountered, then the
1810   *                               {@code LDAPSearchException} object may be
1811   *                               examined to obtain information about those
1812   *                               entries and/or references.
1813   */
1814  public final SearchResult search(final String baseDN, final SearchScope scope,
1815                                   final DereferencePolicy derefPolicy,
1816                                   final int sizeLimit, final int timeLimit,
1817                                   final boolean typesOnly, final Filter filter,
1818                                   final String... attributes)
1819         throws LDAPSearchException
1820  {
1821    return search(new SearchRequest(baseDN, scope, derefPolicy, sizeLimit,
1822         timeLimit, typesOnly, filter, attributes));
1823  }
1824
1825
1826
1827  /**
1828   * Processes a search operation with the provided information using a
1829   * connection from this connection pool.
1830   * <BR><BR>
1831   * Note that if the search does not complete successfully, an
1832   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1833   * search result entries or references may have been returned before the
1834   * failure response is received.  In this case, the
1835   * {@code LDAPSearchException} methods like {@code getEntryCount},
1836   * {@code getSearchEntries}, {@code getReferenceCount}, and
1837   * {@code getSearchReferences} may be used to obtain information about those
1838   * entries and references (although if a search result listener was provided,
1839   * then it will have been used to make any entries and references available,
1840   * and they will not be available through the {@code getSearchEntries} and
1841   * {@code getSearchReferences} methods).
1842   *
1843   * @param  searchResultListener  The search result listener that should be
1844   *                               used to return results to the client.  It may
1845   *                               be {@code null} if the search results should
1846   *                               be collected internally and returned in the
1847   *                               {@code SearchResult} object.
1848   * @param  baseDN                The base DN for the search request.  It must
1849   *                               not be {@code null}.
1850   * @param  scope                 The scope that specifies the range of entries
1851   *                               that should be examined for the search.
1852   * @param  derefPolicy           The dereference policy the server should use
1853   *                               for any aliases encountered while processing
1854   *                               the search.
1855   * @param  sizeLimit             The maximum number of entries that the server
1856   *                               should return for the search.  A value of
1857   *                               zero indicates that there should be no limit.
1858   * @param  timeLimit             The maximum length of time in seconds that
1859   *                               the server should spend processing this
1860   *                               search request.  A value of zero indicates
1861   *                               that there should be no limit.
1862   * @param  typesOnly             Indicates whether to return only attribute
1863   *                               names in matching entries, or both attribute
1864   *                               names and values.
1865   * @param  filter                The string representation of the filter to
1866   *                               use to identify matching entries.  It must
1867   *                               not be {@code null}.
1868   * @param  attributes            The set of attributes that should be returned
1869   *                               in matching entries.  It may be {@code null}
1870   *                               or empty if the default attribute set (all
1871   *                               user attributes) is to be requested.
1872   *
1873   * @return  A search result object that provides information about the
1874   *          processing of the search, potentially including the set of
1875   *          matching entries and search references returned by the server.
1876   *
1877   * @throws  LDAPSearchException  If the search does not complete successfully,
1878   *                               or if a problem is encountered while parsing
1879   *                               the provided filter string, sending the
1880   *                               request, or reading the response.  If one
1881   *                               or more entries or references were returned
1882   *                               before the failure was encountered, then the
1883   *                               {@code LDAPSearchException} object may be
1884   *                               examined to obtain information about those
1885   *                               entries and/or references.
1886   */
1887  public final SearchResult
1888       search(final SearchResultListener searchResultListener,
1889              final String baseDN, final SearchScope scope,
1890              final DereferencePolicy derefPolicy, final int sizeLimit,
1891              final int timeLimit, final boolean typesOnly, final String filter,
1892              final String... attributes)
1893         throws LDAPSearchException
1894  {
1895    return search(new SearchRequest(searchResultListener, baseDN, scope,
1896         derefPolicy, sizeLimit, timeLimit, typesOnly, parseFilter(filter),
1897         attributes));
1898  }
1899
1900
1901
1902  /**
1903   * Processes a search operation with the provided information using a
1904   * connection from this connection pool.
1905   * <BR><BR>
1906   * Note that if the search does not complete successfully, an
1907   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1908   * search result entries or references may have been returned before the
1909   * failure response is received.  In this case, the
1910   * {@code LDAPSearchException} methods like {@code getEntryCount},
1911   * {@code getSearchEntries}, {@code getReferenceCount}, and
1912   * {@code getSearchReferences} may be used to obtain information about those
1913   * entries and references (although if a search result listener was provided,
1914   * then it will have been used to make any entries and references available,
1915   * and they will not be available through the {@code getSearchEntries} and
1916   * {@code getSearchReferences} methods).
1917   *
1918   * @param  searchResultListener  The search result listener that should be
1919   *                               used to return results to the client.  It may
1920   *                               be {@code null} if the search results should
1921   *                               be collected internally and returned in the
1922   *                               {@code SearchResult} object.
1923   * @param  baseDN                The base DN for the search request.  It must
1924   *                               not be {@code null}.
1925   * @param  scope                 The scope that specifies the range of entries
1926   *                               that should be examined for the search.
1927   * @param  derefPolicy           The dereference policy the server should use
1928   *                               for any aliases encountered while processing
1929   *                               the search.
1930   * @param  sizeLimit             The maximum number of entries that the server
1931   *                               should return for the search.  A value of
1932   *                               zero indicates that there should be no limit.
1933   * @param  timeLimit             The maximum length of time in seconds that
1934   *                               the server should spend processing this
1935   *                               search request.  A value of zero indicates
1936   *                               that there should be no limit.
1937   * @param  typesOnly             Indicates whether to return only attribute
1938   *                               names in matching entries, or both attribute
1939   *                               names and values.
1940   * @param  filter                The filter to use to identify matching
1941   *                               entries.  It must not be {@code null}.
1942   * @param  attributes            The set of attributes that should be returned
1943   *                               in matching entries.  It may be {@code null}
1944   *                               or empty if the default attribute set (all
1945   *                               user attributes) is to be requested.
1946   *
1947   * @return  A search result object that provides information about the
1948   *          processing of the search, potentially including the set of
1949   *          matching entries and search references returned by the server.
1950   *
1951   * @throws  LDAPSearchException  If the search does not complete successfully,
1952   *                               or if a problem is encountered while sending
1953   *                               the request or reading the response.  If one
1954   *                               or more entries or references were returned
1955   *                               before the failure was encountered, then the
1956   *                               {@code LDAPSearchException} object may be
1957   *                               examined to obtain information about those
1958   *                               entries and/or references.
1959   */
1960  public final SearchResult
1961        search(final SearchResultListener searchResultListener,
1962               final String baseDN, final SearchScope scope,
1963               final DereferencePolicy derefPolicy, final int sizeLimit,
1964               final int timeLimit, final boolean typesOnly,
1965               final Filter filter, final String... attributes)
1966         throws LDAPSearchException
1967  {
1968    return search(new SearchRequest(searchResultListener, baseDN, scope,
1969         derefPolicy, sizeLimit, timeLimit, typesOnly, filter, attributes));
1970  }
1971
1972
1973
1974  /**
1975   * Processes the provided search request using a connection from this
1976   * connection pool.
1977   * <BR><BR>
1978   * Note that if the search does not complete successfully, an
1979   * {@code LDAPSearchException} will be thrown  In some cases, one or more
1980   * search result entries or references may have been returned before the
1981   * failure response is received.  In this case, the
1982   * {@code LDAPSearchException} methods like {@code getEntryCount},
1983   * {@code getSearchEntries}, {@code getReferenceCount}, and
1984   * {@code getSearchReferences} may be used to obtain information about those
1985   * entries and references (although if a search result listener was provided,
1986   * then it will have been used to make any entries and references available,
1987   * and they will not be available through the {@code getSearchEntries} and
1988   * {@code getSearchReferences} methods).
1989   *
1990   * @param  searchRequest  The search request to be processed.  It must not be
1991   *                        {@code null}.
1992   *
1993   * @return  A search result object that provides information about the
1994   *          processing of the search, potentially including the set of
1995   *          matching entries and search references returned by the server.
1996   *
1997   * @throws  LDAPSearchException  If the search does not complete successfully,
1998   *                               or if a problem is encountered while sending
1999   *                               the request or reading the response.  If one
2000   *                               or more entries or references were returned
2001   *                               before the failure was encountered, then the
2002   *                               {@code LDAPSearchException} object may be
2003   *                               examined to obtain information about those
2004   *                               entries and/or references.
2005   */
2006  public final SearchResult search(final SearchRequest searchRequest)
2007         throws LDAPSearchException
2008  {
2009    final LDAPConnection conn;
2010    try
2011    {
2012      conn = getConnection();
2013    }
2014    catch (LDAPException le)
2015    {
2016      debugException(le);
2017      throw new LDAPSearchException(le);
2018    }
2019
2020    try
2021    {
2022      final SearchResult result = conn.search(searchRequest);
2023      releaseConnection(conn);
2024      return result;
2025    }
2026    catch (Throwable t)
2027    {
2028      throwLDAPSearchExceptionIfShouldNotRetry(t, conn);
2029
2030      // If we have gotten here, then we should retry the operation with a
2031      // newly-created connection.
2032      final LDAPConnection newConn;
2033      try
2034      {
2035        newConn = replaceDefunctConnection(t, conn);
2036      }
2037      catch (final LDAPException le)
2038      {
2039        debugException(le);
2040        throw new LDAPSearchException(le);
2041      }
2042
2043      try
2044      {
2045        final SearchResult result = newConn.search(searchRequest);
2046        releaseConnection(newConn);
2047        return result;
2048      }
2049      catch (final Throwable t2)
2050      {
2051        throwLDAPSearchException(t2, newConn);
2052      }
2053
2054      // This return statement should never be reached.
2055      return null;
2056    }
2057  }
2058
2059
2060
2061  /**
2062   * Processes the provided search request using a connection from this
2063   * connection pool.
2064   * <BR><BR>
2065   * Note that if the search does not complete successfully, an
2066   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2067   * search result entries or references may have been returned before the
2068   * failure response is received.  In this case, the
2069   * {@code LDAPSearchException} methods like {@code getEntryCount},
2070   * {@code getSearchEntries}, {@code getReferenceCount}, and
2071   * {@code getSearchReferences} may be used to obtain information about those
2072   * entries and references (although if a search result listener was provided,
2073   * then it will have been used to make any entries and references available,
2074   * and they will not be available through the {@code getSearchEntries} and
2075   * {@code getSearchReferences} methods).
2076   *
2077   * @param  searchRequest  The search request to be processed.  It must not be
2078   *                        {@code null}.
2079   *
2080   * @return  A search result object that provides information about the
2081   *          processing of the search, potentially including the set of
2082   *          matching entries and search references returned by the server.
2083   *
2084   * @throws  LDAPSearchException  If the search does not complete successfully,
2085   *                               or if a problem is encountered while sending
2086   *                               the request or reading the response.  If one
2087   *                               or more entries or references were returned
2088   *                               before the failure was encountered, then the
2089   *                               {@code LDAPSearchException} object may be
2090   *                               examined to obtain information about those
2091   *                               entries and/or references.
2092   */
2093  public final SearchResult search(final ReadOnlySearchRequest searchRequest)
2094         throws LDAPSearchException
2095  {
2096    return search((SearchRequest) searchRequest);
2097  }
2098
2099
2100
2101  /**
2102   * Processes a search operation with the provided information using a
2103   * connection from this connection pool.  It is expected that at most one
2104   * entry will be returned from the search, and that no additional content from
2105   * the successful search result (e.g., diagnostic message or response
2106   * controls) are needed.
2107   * <BR><BR>
2108   * Note that if the search does not complete successfully, an
2109   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2110   * search result entries or references may have been returned before the
2111   * failure response is received.  In this case, the
2112   * {@code LDAPSearchException} methods like {@code getEntryCount},
2113   * {@code getSearchEntries}, {@code getReferenceCount}, and
2114   * {@code getSearchReferences} may be used to obtain information about those
2115   * entries and references.
2116   *
2117   * @param  baseDN      The base DN for the search request.  It must not be
2118   *                     {@code null}.
2119   * @param  scope       The scope that specifies the range of entries that
2120   *                     should be examined for the search.
2121   * @param  filter      The string representation of the filter to use to
2122   *                     identify matching entries.  It must not be
2123   *                     {@code null}.
2124   * @param  attributes  The set of attributes that should be returned in
2125   *                     matching entries.  It may be {@code null} or empty if
2126   *                     the default attribute set (all user attributes) is to
2127   *                     be requested.
2128   *
2129   * @return  The entry that was returned from the search, or {@code null} if no
2130   *          entry was returned or the base entry does not exist.
2131   *
2132   * @throws  LDAPSearchException  If the search does not complete successfully,
2133   *                               if more than a single entry is returned, or
2134   *                               if a problem is encountered while parsing the
2135   *                               provided filter string, sending the request,
2136   *                               or reading the response.  If one or more
2137   *                               entries or references were returned before
2138   *                               the failure was encountered, then the
2139   *                               {@code LDAPSearchException} object may be
2140   *                               examined to obtain information about those
2141   *                               entries and/or references.
2142   */
2143  public final SearchResultEntry searchForEntry(final String baseDN,
2144                                                final SearchScope scope,
2145                                                final String filter,
2146                                                final String... attributes)
2147         throws LDAPSearchException
2148  {
2149    return searchForEntry(new SearchRequest(baseDN, scope,
2150         DereferencePolicy.NEVER, 1, 0, false, parseFilter(filter),
2151         attributes));
2152  }
2153
2154
2155
2156  /**
2157   * Processes a search operation with the provided information using a
2158   * connection from this connection pool.  It is expected that at most one
2159   * entry will be returned from the search, and that no additional content from
2160   * the successful search result (e.g., diagnostic message or response
2161   * controls) are needed.
2162   * <BR><BR>
2163   * Note that if the search does not complete successfully, an
2164   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2165   * search result entries or references may have been returned before the
2166   * failure response is received.  In this case, the
2167   * {@code LDAPSearchException} methods like {@code getEntryCount},
2168   * {@code getSearchEntries}, {@code getReferenceCount}, and
2169   * {@code getSearchReferences} may be used to obtain information about those
2170   * entries and references.
2171   *
2172   * @param  baseDN      The base DN for the search request.  It must not be
2173   *                     {@code null}.
2174   * @param  scope       The scope that specifies the range of entries that
2175   *                     should be examined for the search.
2176   * @param  filter      The string representation of the filter to use to
2177   *                     identify matching entries.  It must not be
2178   *                     {@code null}.
2179   * @param  attributes  The set of attributes that should be returned in
2180   *                     matching entries.  It may be {@code null} or empty if
2181   *                     the default attribute set (all user attributes) is to
2182   *                     be requested.
2183   *
2184   * @return  The entry that was returned from the search, or {@code null} if no
2185   *          entry was returned or the base entry does not exist.
2186   *
2187   * @throws  LDAPSearchException  If the search does not complete successfully,
2188   *                               if more than a single entry is returned, or
2189   *                               if a problem is encountered while parsing the
2190   *                               provided filter string, sending the request,
2191   *                               or reading the response.  If one or more
2192   *                               entries or references were returned before
2193   *                               the failure was encountered, then the
2194   *                               {@code LDAPSearchException} object may be
2195   *                               examined to obtain information about those
2196   *                               entries and/or references.
2197   */
2198  public final SearchResultEntry searchForEntry(final String baseDN,
2199                                                final SearchScope scope,
2200                                                final Filter filter,
2201                                                final String... attributes)
2202         throws LDAPSearchException
2203  {
2204    return searchForEntry(new SearchRequest(baseDN, scope,
2205         DereferencePolicy.NEVER, 1, 0, false, filter, attributes));
2206  }
2207
2208
2209
2210  /**
2211   * Processes a search operation with the provided information using a
2212   * connection from this connection pool.  It is expected that at most one
2213   * entry will be returned from the search, and that no additional content from
2214   * the successful search result (e.g., diagnostic message or response
2215   * controls) are needed.
2216   * <BR><BR>
2217   * Note that if the search does not complete successfully, an
2218   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2219   * search result entries or references may have been returned before the
2220   * failure response is received.  In this case, the
2221   * {@code LDAPSearchException} methods like {@code getEntryCount},
2222   * {@code getSearchEntries}, {@code getReferenceCount}, and
2223   * {@code getSearchReferences} may be used to obtain information about those
2224   * entries and references.
2225   *
2226   * @param  baseDN       The base DN for the search request.  It must not be
2227   *                      {@code null}.
2228   * @param  scope        The scope that specifies the range of entries that
2229   *                      should be examined for the search.
2230   * @param  derefPolicy  The dereference policy the server should use for any
2231   *                      aliases encountered while processing the search.
2232   * @param  timeLimit    The maximum length of time in seconds that the server
2233   *                      should spend processing this search request.  A value
2234   *                      of zero indicates that there should be no limit.
2235   * @param  typesOnly    Indicates whether to return only attribute names in
2236   *                      matching entries, or both attribute names and values.
2237   * @param  filter       The string representation of the filter to use to
2238   *                      identify matching entries.  It must not be
2239   *                      {@code null}.
2240   * @param  attributes   The set of attributes that should be returned in
2241   *                      matching entries.  It may be {@code null} or empty if
2242   *                      the default attribute set (all user attributes) is to
2243   *                      be requested.
2244   *
2245   * @return  The entry that was returned from the search, or {@code null} if no
2246   *          entry was returned or the base entry does not exist.
2247   *
2248   * @throws  LDAPSearchException  If the search does not complete successfully,
2249   *                               if more than a single entry is returned, or
2250   *                               if a problem is encountered while parsing the
2251   *                               provided filter string, sending the request,
2252   *                               or reading the response.  If one or more
2253   *                               entries or references were returned before
2254   *                               the failure was encountered, then the
2255   *                               {@code LDAPSearchException} object may be
2256   *                               examined to obtain information about those
2257   *                               entries and/or references.
2258   */
2259  public final SearchResultEntry
2260       searchForEntry(final String baseDN, final SearchScope scope,
2261                      final DereferencePolicy derefPolicy, final int timeLimit,
2262                      final boolean typesOnly, final String filter,
2263                      final String... attributes)
2264         throws LDAPSearchException
2265  {
2266    return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1,
2267         timeLimit, typesOnly, parseFilter(filter), attributes));
2268  }
2269
2270
2271
2272  /**
2273   * Processes a search operation with the provided information using a
2274   * connection from this connection pool.  It is expected that at most one
2275   * entry will be returned from the search, and that no additional content from
2276   * the successful search result (e.g., diagnostic message or response
2277   * controls) are needed.
2278   * <BR><BR>
2279   * Note that if the search does not complete successfully, an
2280   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2281   * search result entries or references may have been returned before the
2282   * failure response is received.  In this case, the
2283   * {@code LDAPSearchException} methods like {@code getEntryCount},
2284   * {@code getSearchEntries}, {@code getReferenceCount}, and
2285   * {@code getSearchReferences} may be used to obtain information about those
2286   * entries and references.
2287   *
2288   * @param  baseDN       The base DN for the search request.  It must not be
2289   *                      {@code null}.
2290   * @param  scope        The scope that specifies the range of entries that
2291   *                      should be examined for the search.
2292   * @param  derefPolicy  The dereference policy the server should use for any
2293   *                      aliases encountered while processing the search.
2294   * @param  timeLimit    The maximum length of time in seconds that the server
2295   *                      should spend processing this search request.  A value
2296   *                      of zero indicates that there should be no limit.
2297   * @param  typesOnly    Indicates whether to return only attribute names in
2298   *                      matching entries, or both attribute names and values.
2299   * @param  filter       The filter to use to identify matching entries.  It
2300   *                      must not be {@code null}.
2301   * @param  attributes   The set of attributes that should be returned in
2302   *                      matching entries.  It may be {@code null} or empty if
2303   *                      the default attribute set (all user attributes) is to
2304   *                      be requested.
2305   *
2306   * @return  The entry that was returned from the search, or {@code null} if no
2307   *          entry was returned or the base entry does not exist.
2308   *
2309   * @throws  LDAPSearchException  If the search does not complete successfully,
2310   *                               if more than a single entry is returned, or
2311   *                               if a problem is encountered while parsing the
2312   *                               provided filter string, sending the request,
2313   *                               or reading the response.  If one or more
2314   *                               entries or references were returned before
2315   *                               the failure was encountered, then the
2316   *                               {@code LDAPSearchException} object may be
2317   *                               examined to obtain information about those
2318   *                               entries and/or references.
2319   */
2320  public final SearchResultEntry
2321       searchForEntry(final String baseDN, final SearchScope scope,
2322                      final DereferencePolicy derefPolicy, final int timeLimit,
2323                      final boolean typesOnly, final Filter filter,
2324                      final String... attributes)
2325         throws LDAPSearchException
2326  {
2327    return searchForEntry(new SearchRequest(baseDN, scope, derefPolicy, 1,
2328         timeLimit, typesOnly, filter, attributes));
2329  }
2330
2331
2332
2333  /**
2334   * Processes a search operation with the provided information using a
2335   * connection from this connection pool.  It is expected that at most one
2336   * entry will be returned from the search, and that no additional content from
2337   * the successful search result (e.g., diagnostic message or response
2338   * controls) are needed.
2339   * <BR><BR>
2340   * Note that if the search does not complete successfully, an
2341   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2342   * search result entries or references may have been returned before the
2343   * failure response is received.  In this case, the
2344   * {@code LDAPSearchException} methods like {@code getEntryCount},
2345   * {@code getSearchEntries}, {@code getReferenceCount}, and
2346   * {@code getSearchReferences} may be used to obtain information about those
2347   * entries and references.
2348   *
2349   * @param  searchRequest  The search request to be processed.  If it is
2350   *                        configured with a search result listener or a size
2351   *                        limit other than one, then the provided request will
2352   *                        be duplicated with the appropriate settings.
2353   *
2354   * @return  The entry that was returned from the search, or {@code null} if no
2355   *          entry was returned or the base entry does not exist.
2356   *
2357   * @throws  LDAPSearchException  If the search does not complete successfully,
2358   *                               if more than a single entry is returned, or
2359   *                               if a problem is encountered while parsing the
2360   *                               provided filter string, sending the request,
2361   *                               or reading the response.  If one or more
2362   *                               entries or references were returned before
2363   *                               the failure was encountered, then the
2364   *                               {@code LDAPSearchException} object may be
2365   *                               examined to obtain information about those
2366   *                               entries and/or references.
2367   */
2368  public final SearchResultEntry searchForEntry(
2369                                      final SearchRequest searchRequest)
2370         throws LDAPSearchException
2371  {
2372    final LDAPConnection conn;
2373    try
2374    {
2375      conn = getConnection();
2376    }
2377    catch (LDAPException le)
2378    {
2379      debugException(le);
2380      throw new LDAPSearchException(le);
2381    }
2382
2383    try
2384    {
2385      final SearchResultEntry entry = conn.searchForEntry(searchRequest);
2386      releaseConnection(conn);
2387      return entry;
2388    }
2389    catch (Throwable t)
2390    {
2391      throwLDAPSearchExceptionIfShouldNotRetry(t, conn);
2392
2393      // If we have gotten here, then we should retry the operation with a
2394      // newly-created connection.
2395      final LDAPConnection newConn;
2396      try
2397      {
2398        newConn = replaceDefunctConnection(t, conn);
2399      }
2400      catch (final LDAPException le)
2401      {
2402        debugException(le);
2403        throw new LDAPSearchException(le);
2404      }
2405
2406      try
2407      {
2408        final SearchResultEntry entry = newConn.searchForEntry(searchRequest);
2409        releaseConnection(newConn);
2410        return entry;
2411      }
2412      catch (final Throwable t2)
2413      {
2414        throwLDAPSearchException(t2, newConn);
2415      }
2416
2417      // This return statement should never be reached.
2418      return null;
2419    }
2420  }
2421
2422
2423
2424  /**
2425   * Processes a search operation with the provided information using a
2426   * connection from this connection pool.  It is expected that at most one
2427   * entry will be returned from the search, and that no additional content from
2428   * the successful search result (e.g., diagnostic message or response
2429   * controls) are needed.
2430   * <BR><BR>
2431   * Note that if the search does not complete successfully, an
2432   * {@code LDAPSearchException} will be thrown  In some cases, one or more
2433   * search result entries or references may have been returned before the
2434   * failure response is received.  In this case, the
2435   * {@code LDAPSearchException} methods like {@code getEntryCount},
2436   * {@code getSearchEntries}, {@code getReferenceCount}, and
2437   * {@code getSearchReferences} may be used to obtain information about those
2438   * entries and references.
2439   *
2440   * @param  searchRequest  The search request to be processed.  If it is
2441   *                        configured with a search result listener or a size
2442   *                        limit other than one, then the provided request will
2443   *                        be duplicated with the appropriate settings.
2444   *
2445   * @return  The entry that was returned from the search, or {@code null} if no
2446   *          entry was returned or the base entry does not exist.
2447   *
2448   * @throws  LDAPSearchException  If the search does not complete successfully,
2449   *                               if more than a single entry is returned, or
2450   *                               if a problem is encountered while parsing the
2451   *                               provided filter string, sending the request,
2452   *                               or reading the response.  If one or more
2453   *                               entries or references were returned before
2454   *                               the failure was encountered, then the
2455   *                               {@code LDAPSearchException} object may be
2456   *                               examined to obtain information about those
2457   *                               entries and/or references.
2458   */
2459  public final SearchResultEntry searchForEntry(
2460                                      final ReadOnlySearchRequest searchRequest)
2461         throws LDAPSearchException
2462  {
2463    return searchForEntry((SearchRequest) searchRequest);
2464  }
2465
2466
2467
2468  /**
2469   * Parses the provided string as a {@code Filter} object.
2470   *
2471   * @param  filterString  The string to parse as a {@code Filter}.
2472   *
2473   * @return  The parsed {@code Filter}.
2474   *
2475   * @throws  LDAPSearchException  If the provided string does not represent a
2476   *                               valid search filter.
2477   */
2478  private static Filter parseFilter(final String filterString)
2479          throws LDAPSearchException
2480  {
2481    try
2482    {
2483      return Filter.create(filterString);
2484    }
2485    catch (final LDAPException le)
2486    {
2487      debugException(le);
2488      throw new LDAPSearchException(le);
2489    }
2490  }
2491
2492
2493
2494  /**
2495   * Processes multiple requests in the order they are provided over a single
2496   * connection from this pool.  Note that the
2497   * {@link #retryFailedOperationsDueToInvalidConnections()} setting will be
2498   * ignored when processing the provided operations, so that any failed
2499   * operations will not be retried.
2500   *
2501   * @param  requests         The list of requests to be processed.  It must not
2502   *                          be {@code null} or empty.
2503   * @param  continueOnError  Indicates whether to attempt to process subsequent
2504   *                          requests if any of the operations does not
2505   *                          complete successfully.
2506   *
2507   * @return  The set of results from the requests that were processed.  The
2508   *          order of result objects will correspond to the order of the
2509   *          request objects, although the list of results may contain fewer
2510   *          elements than the list of requests if an error occurred during
2511   *          processing and {@code continueOnError} is {@code false}.
2512   *
2513   * @throws  LDAPException  If a problem occurs while trying to obtain a
2514   *                         connection to use for the requests.
2515   */
2516  public final List<LDAPResult> processRequests(
2517                                     final List<LDAPRequest> requests,
2518                                     final boolean continueOnError)
2519         throws LDAPException
2520  {
2521    ensureNotNull(requests);
2522    ensureFalse(requests.isEmpty(),
2523         "LDAPConnectionPool.processRequests.requests must not be empty.");
2524
2525    final LDAPConnection conn;
2526    try
2527    {
2528      conn = getConnection();
2529    }
2530    catch (LDAPException le)
2531    {
2532      debugException(le);
2533      throw new LDAPSearchException(le);
2534    }
2535
2536    final ArrayList<LDAPResult> results =
2537         new ArrayList<LDAPResult>(requests.size());
2538    boolean isDefunct = false;
2539
2540    try
2541    {
2542requestLoop:
2543      for (final LDAPRequest request : requests)
2544      {
2545        try
2546        {
2547          final LDAPResult result = request.process(conn, 1);
2548          results.add(result);
2549          switch (result.getResultCode().intValue())
2550          {
2551            case ResultCode.SUCCESS_INT_VALUE:
2552            case ResultCode.COMPARE_FALSE_INT_VALUE:
2553            case ResultCode.COMPARE_TRUE_INT_VALUE:
2554            case ResultCode.NO_OPERATION_INT_VALUE:
2555              // These will be considered successful operations.
2556              break;
2557
2558            default:
2559              // Anything else will be considered a failure.
2560              if (! ResultCode.isConnectionUsable(result.getResultCode()))
2561              {
2562                isDefunct = true;
2563              }
2564
2565              if (! continueOnError)
2566              {
2567                break requestLoop;
2568              }
2569              break;
2570          }
2571        }
2572        catch (LDAPException le)
2573        {
2574          debugException(le);
2575          results.add(new LDAPResult(request.getLastMessageID(),
2576                                     le.getResultCode(), le.getMessage(),
2577                                     le.getMatchedDN(), le.getReferralURLs(),
2578                                     le.getResponseControls()));
2579
2580          if (! ResultCode.isConnectionUsable(le.getResultCode()))
2581          {
2582            isDefunct = true;
2583          }
2584
2585          if (! continueOnError)
2586          {
2587            break;
2588          }
2589        }
2590      }
2591    }
2592    finally
2593    {
2594      if (isDefunct)
2595      {
2596        releaseDefunctConnection(conn);
2597      }
2598      else
2599      {
2600        releaseConnection(conn);
2601      }
2602    }
2603
2604    return results;
2605  }
2606
2607
2608
2609  /**
2610   * Processes multiple requests over a single connection from this pool using
2611   * asynchronous processing to cause the operations to be processed
2612   * concurrently.  The list of requests may contain only add, compare, delete,
2613   * modify, modify DN, and search operations (and any search operations to be
2614   * processed must be configured with an {@link AsyncSearchResultListener}.
2615   * This method will not return until all operations have completed, or until
2616   * the specified timeout period has elapsed.  The order of elements in the
2617   * list of the {@link AsyncRequestID} objects returned will correspond to the
2618   * order of elements in the list of requests.  The operation results may be
2619   * obtained from the returned {@code AsyncRequestID} objects using the
2620   * {@code java.util.concurrent.Future} API.
2621   *
2622   * @param  requests           The list of requests to be processed.  It must
2623   *                            not be {@code null} or empty, and it must
2624   *                            contain only add, compare, modify, modify DN,
2625   *                            and search requests.  Any search requests must
2626   *                            be configured with an
2627   *                            {@code AsyncSearchResultListener}.
2628   * @param  maxWaitTimeMillis  The maximum length of time in milliseconds to
2629   *                            wait for the operations to complete before
2630   *                            returning.  A value that is less than or equal
2631   *                            to zero indicates that the client should wait
2632   *                            indefinitely for the operations to complete.
2633   *
2634   * @return  The list of {@code AsyncRequestID} objects that may be used to
2635   *          retrieve the results for the operations.  The order of elements in
2636   *          this list will correspond to the order of the provided requests.
2637   *
2638   * @throws  LDAPException  If there is a problem with any of the requests, or
2639   *                         if connections in the pool are configured to use
2640   *                         synchronous mode and therefore cannot be used to
2641   *                         process asynchronous operations.
2642   */
2643  public final List<AsyncRequestID> processRequestsAsync(
2644                                         final List<LDAPRequest> requests,
2645                                         final long maxWaitTimeMillis)
2646         throws LDAPException
2647  {
2648    // Make sure the set of requests is not null or empty.
2649    ensureNotNull(requests);
2650    ensureFalse(requests.isEmpty(),
2651         "LDAPConnectionPool.processRequests.requests must not be empty.");
2652
2653    // Make sure that all the requests are acceptable.
2654    for (final LDAPRequest r : requests)
2655    {
2656      switch (r.getOperationType())
2657      {
2658        case ADD:
2659        case COMPARE:
2660        case DELETE:
2661        case MODIFY:
2662        case MODIFY_DN:
2663          // These operation types are always acceptable for asynchronous
2664          // processing.
2665          break;
2666
2667        case SEARCH:
2668          // Search operations will only be acceptable if they have been
2669          // configured with an async search result listener.
2670          final SearchRequest searchRequest = (SearchRequest) r;
2671          if ((searchRequest.getSearchResultListener() == null) ||
2672              (! (searchRequest.getSearchResultListener() instanceof
2673                   AsyncSearchResultListener)))
2674          {
2675            throw new LDAPException(ResultCode.PARAM_ERROR,
2676                 ERR_POOL_PROCESS_REQUESTS_ASYNC_SEARCH_NOT_ASYNC.get(
2677                      String.valueOf(r)));
2678          }
2679          break;
2680
2681        case ABANDON:
2682        case BIND:
2683        case EXTENDED:
2684        case UNBIND:
2685        default:
2686          // These operation types are never acceptable for asynchronous
2687          // processing.
2688          throw new LDAPException(ResultCode.PARAM_ERROR,
2689               ERR_POOL_PROCESS_REQUESTS_ASYNC_OP_NOT_ASYNC.get(
2690                    String.valueOf(r)));
2691      }
2692    }
2693
2694
2695    final LDAPConnection conn;
2696    try
2697    {
2698      conn = getConnection();
2699    }
2700    catch (LDAPException le)
2701    {
2702      debugException(le);
2703      throw new LDAPSearchException(le);
2704    }
2705
2706
2707    final ArrayList<AsyncRequestID> requestIDs =
2708         new ArrayList<AsyncRequestID>();
2709    boolean isDefunct = false;
2710
2711    try
2712    {
2713      // Make sure that the connection is not configured to use synchronous
2714      // mode, because asynchronous operations are not allowed in that mode.
2715      if (conn.synchronousMode())
2716      {
2717        throw new LDAPException(ResultCode.PARAM_ERROR,
2718             ERR_POOL_PROCESS_REQUESTS_ASYNC_SYNCHRONOUS_MODE.get());
2719      }
2720
2721
2722      // Issue all of the requests.  If an exception is encountered while
2723      // issuing a request, then convert it into an AsyncRequestID with the
2724      // exception as the result.
2725      for (final LDAPRequest r : requests)
2726      {
2727        AsyncRequestID requestID = null;
2728        try
2729        {
2730          switch (r.getOperationType())
2731          {
2732            case ADD:
2733              requestID = conn.asyncAdd((AddRequest) r, null);
2734              break;
2735            case COMPARE:
2736              requestID = conn.asyncCompare((CompareRequest) r, null);
2737              break;
2738            case DELETE:
2739              requestID = conn.asyncDelete((DeleteRequest) r, null);
2740              break;
2741            case MODIFY:
2742              requestID = conn.asyncModify((ModifyRequest) r, null);
2743              break;
2744            case MODIFY_DN:
2745              requestID = conn.asyncModifyDN((ModifyDNRequest) r, null);
2746              break;
2747            case SEARCH:
2748              requestID = conn.asyncSearch((SearchRequest) r);
2749              break;
2750          }
2751        }
2752        catch (final LDAPException le)
2753        {
2754          debugException(le);
2755          requestID = new AsyncRequestID(r.getLastMessageID(), conn);
2756          requestID.setResult(le.toLDAPResult());
2757        }
2758
2759        requestIDs.add(requestID);
2760      }
2761
2762
2763      // Wait for the operations to complete.  If any operation does not
2764      // complete before the specified timeout, then create a failure result for
2765      // it.  If any operation does not complete successfully, then attempt to
2766      // determine whether the failure may indicate that the connection is no
2767      // longer valid.
2768      final long startWaitingTime = System.currentTimeMillis();
2769      final long stopWaitingTime;
2770      if (maxWaitTimeMillis > 0)
2771      {
2772        stopWaitingTime = startWaitingTime + maxWaitTimeMillis;
2773      }
2774      else
2775      {
2776        stopWaitingTime = Long.MAX_VALUE;
2777      }
2778
2779      for (final AsyncRequestID requestID : requestIDs)
2780      {
2781        LDAPResult result;
2782        final long waitTime = stopWaitingTime - System.currentTimeMillis();
2783        if (waitTime > 0)
2784        {
2785          try
2786          {
2787            result = requestID.get(waitTime, TimeUnit.MILLISECONDS);
2788          }
2789          catch (final Exception e)
2790          {
2791            debugException(e);
2792            requestID.cancel(true);
2793
2794            if (e instanceof TimeoutException)
2795            {
2796              result = new LDAPResult(requestID.getMessageID(),
2797                   ResultCode.TIMEOUT,
2798                   ERR_POOL_PROCESS_REQUESTS_ASYNC_RESULT_TIMEOUT.get(
2799                        (System.currentTimeMillis() - startWaitingTime)),
2800                   null, NO_STRINGS, NO_CONTROLS);
2801            }
2802            else
2803            {
2804              result = new LDAPResult(requestID.getMessageID(),
2805                   ResultCode.LOCAL_ERROR,
2806                   ERR_POOL_PROCESS_REQUESTS_ASYNC_RESULT_EXCEPTION.get(
2807                        getExceptionMessage(e)),
2808                   null, NO_STRINGS, NO_CONTROLS);
2809            }
2810            requestID.setResult(result);
2811          }
2812        }
2813        else
2814        {
2815          requestID.cancel(true);
2816          result = new LDAPResult(requestID.getMessageID(),
2817               ResultCode.TIMEOUT,
2818               ERR_POOL_PROCESS_REQUESTS_ASYNC_RESULT_TIMEOUT.get(
2819                    (System.currentTimeMillis() - startWaitingTime)),
2820               null, NO_STRINGS, NO_CONTROLS);
2821          requestID.setResult(result);
2822        }
2823
2824
2825        // See if we think that the connection may be defunct.
2826        if (! ResultCode.isConnectionUsable(result.getResultCode()))
2827        {
2828          isDefunct = true;
2829        }
2830      }
2831
2832      return requestIDs;
2833    }
2834    finally
2835    {
2836      if (isDefunct)
2837      {
2838        releaseDefunctConnection(conn);
2839      }
2840      else
2841      {
2842        releaseConnection(conn);
2843      }
2844    }
2845  }
2846
2847
2848
2849  /**
2850   * Examines the provided {@code Throwable} object to determine whether it
2851   * represents an {@code LDAPException} that indicates the associated
2852   * connection may no longer be valid.  If that is the case, and if such
2853   * operations should be retried, then no exception will be thrown.  Otherwise,
2854   * an appropriate {@code LDAPException} will be thrown.
2855   *
2856   * @param  t     The {@code Throwable} object that was caught.
2857   * @param  o     The type of operation for which to make the determination.
2858   * @param  conn  The connection to be released to the pool.
2859   *
2860   * @throws  LDAPException  To indicate that a problem occurred during LDAP
2861   *                         processing and the operation should not be retried.
2862   */
2863  private void throwLDAPExceptionIfShouldNotRetry(final Throwable t,
2864                                                  final OperationType o,
2865                                                  final LDAPConnection conn)
2866          throws LDAPException
2867  {
2868    if ((t instanceof LDAPException) &&
2869        getOperationTypesToRetryDueToInvalidConnections().contains(o))
2870    {
2871      final LDAPException le = (LDAPException) t;
2872      final LDAPConnectionPoolHealthCheck healthCheck = getHealthCheck();
2873
2874      try
2875      {
2876        healthCheck.ensureConnectionValidAfterException(conn, le);
2877      }
2878      catch (final Exception e)
2879      {
2880        // If we have gotten this exception, then it indicates that the
2881        // connection is no longer valid and the operation should be retried.
2882        debugException(e);
2883        return;
2884      }
2885    }
2886
2887    throwLDAPException(t, conn);
2888  }
2889
2890
2891
2892  /**
2893   * Examines the provided {@code Throwable} object to determine whether it
2894   * represents an {@code LDAPException} that indicates the associated
2895   * connection may no longer be valid.  If that is the case, and if such
2896   * operations should be retried, then no exception will be thrown.  Otherwise,
2897   * an appropriate {@code LDAPSearchException} will be thrown.
2898   *
2899   * @param  t     The {@code Throwable} object that was caught.
2900   * @param  conn  The connection to be released to the pool.
2901   *
2902   * @throws  LDAPSearchException  To indicate that a problem occurred during
2903   *                               LDAP processing and the operation should not
2904   *                               be retried.
2905   */
2906  private void throwLDAPSearchExceptionIfShouldNotRetry(final Throwable t,
2907                    final LDAPConnection conn)
2908          throws LDAPSearchException
2909  {
2910    if ((t instanceof LDAPException) &&
2911        getOperationTypesToRetryDueToInvalidConnections().contains(
2912             OperationType.SEARCH))
2913    {
2914      final LDAPException le = (LDAPException) t;
2915      final LDAPConnectionPoolHealthCheck healthCheck = getHealthCheck();
2916
2917      try
2918      {
2919        healthCheck.ensureConnectionValidAfterException(conn, le);
2920      }
2921      catch (final Exception e)
2922      {
2923        // If we have gotten this exception, then it indicates that the
2924        // connection is no longer valid and the operation should be retried.
2925        debugException(e);
2926        return;
2927      }
2928    }
2929
2930    throwLDAPSearchException(t, conn);
2931  }
2932
2933
2934
2935  /**
2936   * Handles the provided {@code Throwable} object by ensuring that the provided
2937   * connection is released to the pool and throwing an appropriate
2938   * {@code LDAPException} object.
2939   *
2940   * @param  t     The {@code Throwable} object that was caught.
2941   * @param  conn  The connection to be released to the pool.
2942   *
2943   * @throws  LDAPException  To indicate that a problem occurred during LDAP
2944   *                         processing.
2945   */
2946  void throwLDAPException(final Throwable t, final LDAPConnection conn)
2947       throws LDAPException
2948  {
2949    debugException(t);
2950    if (t instanceof LDAPException)
2951    {
2952      final LDAPException le = (LDAPException) t;
2953      releaseConnectionAfterException(conn, le);
2954      throw le;
2955    }
2956    else
2957    {
2958      releaseDefunctConnection(conn);
2959      throw new LDAPException(ResultCode.LOCAL_ERROR,
2960           ERR_POOL_OP_EXCEPTION.get(getExceptionMessage(t)), t);
2961    }
2962  }
2963
2964
2965
2966  /**
2967   * Handles the provided {@code Throwable} object by ensuring that the provided
2968   * connection is released to the pool and throwing an appropriate
2969   * {@code LDAPSearchException} object.
2970   *
2971   * @param  t     The {@code Throwable} object that was caught.
2972   * @param  conn  The connection to be released to the pool.
2973   *
2974   * @throws  LDAPSearchException  To indicate that a problem occurred during
2975   *                               LDAP search processing.
2976   */
2977  void throwLDAPSearchException(final Throwable t, final LDAPConnection conn)
2978       throws LDAPSearchException
2979  {
2980    debugException(t);
2981    if (t instanceof LDAPException)
2982    {
2983      final LDAPSearchException lse;
2984      if (t instanceof LDAPSearchException)
2985      {
2986        lse = (LDAPSearchException) t;
2987      }
2988      else
2989      {
2990        lse = new LDAPSearchException((LDAPException) t);
2991      }
2992
2993      releaseConnectionAfterException(conn, lse);
2994      throw lse;
2995    }
2996    else
2997    {
2998      releaseDefunctConnection(conn);
2999      throw new LDAPSearchException(ResultCode.LOCAL_ERROR,
3000           ERR_POOL_OP_EXCEPTION.get(getExceptionMessage(t)), t);
3001    }
3002  }
3003
3004
3005
3006  /**
3007   * Retrieves a string representation of this connection pool.
3008   *
3009   * @return  A string representation of this connection pool.
3010   */
3011  @Override()
3012  public final String toString()
3013  {
3014    final StringBuilder buffer = new StringBuilder();
3015    toString(buffer);
3016    return buffer.toString();
3017  }
3018
3019
3020
3021  /**
3022   * Appends a string representation of this connection pool to the provided
3023   * buffer.
3024   *
3025   * @param  buffer  The buffer to which the string representation should be
3026   *                 appended.
3027   */
3028  public abstract void toString(final StringBuilder buffer);
3029}