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