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