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