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