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