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