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