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