001/*
002 * Copyright 2009-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2009-2014 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 */
021package com.unboundid.ldap.sdk;
022
023
024
025import java.util.ArrayList;
026import java.util.Collection;
027import java.util.EnumSet;
028import java.util.List;
029import java.util.Set;
030import java.util.concurrent.TimeUnit;
031import java.util.concurrent.TimeoutException;
032
033import com.unboundid.asn1.ASN1OctetString;
034import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
035import com.unboundid.ldap.sdk.schema.Schema;
036import com.unboundid.ldif.LDIFException;
037import com.unboundid.util.NotExtensible;
038import com.unboundid.util.ThreadSafety;
039import com.unboundid.util.ThreadSafetyLevel;
040
041import static com.unboundid.ldap.sdk.LDAPMessages.*;
042import static com.unboundid.util.Debug.*;
043import static com.unboundid.util.StaticUtils.*;
044import 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)
054public 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    {
2540requestLoop:
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}