001    /*
002     * Copyright 2009-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.ldap.sdk;
022    
023    
024    
025    
026    import static com.unboundid.ldap.sdk.LDAPMessages.*;
027    import static com.unboundid.util.StaticUtils.*;
028    
029    
030    
031    /**
032     * This class provides an API that may be used to determine whether connections
033     * associated with a connection pool are valid and suitable for use.  It
034     * provides the ability to check the validity of a connection at the following
035     * times:
036     * <UL>
037     *   <LI>Whenever a new connection is created for use in the pool, the
038     *       {@code ensureNewConnectionValid(LDAPConnection)} method will be called
039     *       before making that connection available.  The default implementation
040     *       provided in this class does not perform any kind of processing, but
041     *       subclasses may override this behavior if desired.</LI>
042     *   <LI>Whenever a connection is checked out from the pool (including
043     *       connections checked out internally for operations performed in the
044     *       pool), the {@code ensureConnectionValidForCheckout(LDAPConnection)}
045     *       method will be called.  The default implementation provided in this
046     *       class does not perform any kind of processing, but subclasses may
047     *       override this behavior if desired.</LI>
048     *   <LI>Whenever a connection is released back to the pool (including
049     *       connections checked out internally for operations performed in the
050     *       pool), the {@code ensureConnectionValidForRelease(LDAPConnection)}
051     *       method will be called.  The default implementation provided in this
052     *       class does not perform any kind of processing, but subclasses may
053     *       override this behavior if desired.</LI>
054     *   <LI>The {@code ensureConnectionValidForContinuedUse(LDAPConnection)}
055     *       method will be invoked periodically by a background thread created by
056     *       the connection pool to determine whether available connections within
057     *       the pool are still valid.  The default implementation provided in this
058     *       class does not perform any kind of processing, but subclasses may
059     *       override this behavior if desired.</LI>
060     *   <LI>The {@code ensureConnectionValidAfterException} method may be invoked
061     *       if an exception is caught while processing an operation with a
062     *       connection that is part of a connection pool.  The default
063     *       implementation provided in this class only examines the result code of
064     *       the provided exception and uses the
065     *       {@code ResultCode#isConnectionUsable(ResultCode)} method to make the
066     *       determination, but subclasses may override this behavior if
067     *       desired.</LI>
068     * </UL>
069     * Note that health check implementations should be designed so that they are
070     * suitable for use with connections having any authentication state.  The
071     * {@code ensureNewConnectionValid(LDAPConnection)} method will be invoked on
072     * unauthenticated connections, and the remaining health check methods will be
073     * invoked using whatever credentials are assigned to connections in the
074     * associated connection pool.
075     */
076    public class LDAPConnectionPoolHealthCheck
077    {
078      /**
079       * Creates a new instance of this LDAP connection pool health check.
080       */
081      public LDAPConnectionPoolHealthCheck()
082      {
083        // No implementation is required.
084      }
085    
086    
087    
088      /**
089       * Performs any desired processing to determine whether the provided new
090       * connection is available to be checked out and used for processing
091       * operations.  This method will be invoked by either {@code ServerSet} used
092       * by the connection pool (if it supports enhanced health checking) or by the
093       * connection pool itself at the time that a new connection is created.  No
094       * authentication will have been performed on this connection at the time the
095       * health check is invoked.
096       *
097       * @param  connection  The connection to be examined.
098       *
099       * @throws  LDAPException  If a problem is detected that suggests that the
100       *                         provided connection is not suitable for use.
101       */
102      public void ensureNewConnectionValid(final LDAPConnection connection)
103             throws LDAPException
104      {
105        // No processing is performed in this default implementation.
106      }
107    
108    
109    
110      /**
111       * Performs any desired processing to determine whether the provided
112       * connection is valid after processing a bind operation with the provided
113       * result.
114       * <BR><BR>
115       * This method will be invoked under the following circumstances:
116       * <UL>
117       *   <LI>
118       *     If you create a connection pool with a {@code ServerSet} and a
119       *     non-{@code null} {@code BindRequest}, then this health check method
120       *     will be invoked for every new connection created by the pool after
121       *     processing that {@code BindRequest} on the connection.  If you create a
122       *     connection pool with a {@code ServerSet} but a {@code null}
123       *     {@code BindRequest}, then no authentication will be attempted (and
124       *     therefore this health check method will not be invoked for)
125       *     newly-created connections.
126       *   </LI>
127       *   <LI>
128       *     If you create a connection pool with an {@code LDAPConnection} after
129       *     having performed a bind operation on that connection, then every new
130       *     connection created by the pool will attempt to perform the same type of
131       *     bind operation and this health check method will be invoked after that
132       *     bind attempt has completed.  If you create a connection pool with an
133       *     {@code LDAPConnection} that has not been authenticated, then no
134       *     authentication will be attempted (and therefore this health check
135       *     method will not be invoked for) newly-created connections.
136       *   </LI>
137       *   <LI>
138       *     If you call a connection pool's {@code bindAndRevertAuthentication}
139       *     method, then this health check method will be called after the second
140       *     bind operation (the one used to revert authentication) has completed.
141       *     In this case, this health check method will be called even if the
142       *     connection pool was created with a {@code null} {@code BindRequest} or
143       *     with an unauthenticated {@code LDAPConnection}.  In that case, the
144       *     bind operation used to revert authentication will be a
145       *     {@code SimpleBindRequest} with an empty DN and password.
146       *   </LI>
147       *   <LI>
148       *     If you call a connection pool's
149       *     {@code releaseAndReAuthenticateConnection} method, then this health
150       *     check method will be called after the bind operation has completed.  As
151       *     with {@code bindAndRevertAuthentication}, this health check method will
152       *     be called even if the connection pool was created with a {@code null}
153       *     {@code BindRequest} or with an unauthenticated {@code LDAPConnection}.
154       *   </LI>
155       * </UL>
156       * <BR><BR>
157       * Note that this health check method may be invoked even if the bind
158       * attempt was not successful.  This is useful because it allows the health
159       * check to intercept a failed authentication attempt and differentiate it
160       * from other types of failures in the course of trying to create or check out
161       * a connection.  In the event that it is invoked with a {@code BindResult}
162       * that has a result code other than {@code ResultCode#SUCCESS}, if this
163       * method throws an exception then that exception will be propagated to the
164       * caller.  If this method does not throw an exception when provided with a
165       * non-{@code SUCCESS} result, then the connection pool itself will throw an
166       * exception using the information in the bind result.
167       *
168       * @param  connection  The connection to be examined.
169       * @param  bindResult  The bind result obtained from the authentication
170       *                     process.
171       *
172       * @throws  LDAPException  If a problem is detected that suggests that the
173       *                         provided connection is not suitable for use.
174       */
175      public void ensureConnectionValidAfterAuthentication(
176                       final LDAPConnection connection,
177                       final BindResult bindResult)
178             throws LDAPException
179      {
180        // No processing is performed in this default implementation.
181      }
182    
183    
184    
185      /**
186       * Performs any desired processing to determine whether the provided
187       * connection is available to be checked out and used for processing
188       * operations.  This method will be invoked by the
189       * {@code LDAPConnectionPool#getConnection()} method before handing out a
190       * connection.  This method should return normally if the connection is
191       * believed to be valid, or should throw an {@code LDAPException} if a problem
192       * is detected.
193       *
194       * @param  connection  The connection to be examined.
195       *
196       * @throws  LDAPException  If a problem is detected that suggests that the
197       *                         provided connection is not suitable for use.
198       */
199      public void ensureConnectionValidForCheckout(final LDAPConnection connection)
200             throws LDAPException
201      {
202        // No processing is performed in this default implementation.
203      }
204    
205    
206    
207      /**
208       * Performs any desired processing to determine whether the provided
209       * connection is valid and should be released back to the pool to be used for
210       * processing other operations.  This method will be invoked by the
211       * {@code LDAPConnectionPool#releaseConnection(LDAPConnection)} method before
212       * making the connection available for use in processing other operations.
213       * This method should return normally if the connection is believed to be
214       * valid, or should throw an {@code LDAPException} if a problem is detected.
215       *
216       * @param  connection  The connection to be examined.
217       *
218       * @throws  LDAPException  If a problem is detected that suggests that the
219       *                         provided connection is not suitable for use.
220       */
221      public void ensureConnectionValidForRelease(final LDAPConnection connection)
222             throws LDAPException
223      {
224        // No processing is performed in this default implementation.
225      }
226    
227    
228    
229      /**
230       * Performs any desired processing to determine whether the provided
231       * connection is valid and should continue to be made available for
232       * processing operations.  This method will be periodically invoked by a
233       * background thread used to test availability of connections within the pool.
234       * This method should return normally if the connection is believed to be
235       * valid, or should throw an {@code LDAPException} if a problem is detected.
236       *
237       * @param  connection  The connection to be examined.
238       *
239       * @throws  LDAPException  If a problem is detected that suggests that the
240       *                         provided connection is not suitable for use.
241       */
242      public void ensureConnectionValidForContinuedUse(
243                       final LDAPConnection connection)
244             throws LDAPException
245      {
246        // No processing is performed in this default implementation.
247      }
248    
249    
250    
251      /**
252       * Indicates whether the provided connection may still be considered valid
253       * after an attempt to process an operation yielded the given exception.  This
254       * method will be invoked by the
255       * {@code LDAPConnectionPool#releaseConnectionAfterException} method, and it
256       * may also be manually invoked by external callers if an exception is
257       * encountered while processing an operation on a connection checked out from
258       * the pool.  It may make a determination based solely on the provided
259       * exception, or it may also attempt to use the provided connection to further
260       * test its validity.  This method should return normally if the connection is
261       * believed to be valid, or should throw an {@code LDAPException} if a problem
262       * is detected.
263       *
264       * @param  connection  The connection to be examined.
265       * @param  exception   The exception that was caught while processing an
266       *                     operation on the connection.
267       *
268       * @throws  LDAPException  If a problem is detected that suggests that the
269       *                         provided connection is not suitable for use.
270       */
271      public void ensureConnectionValidAfterException(
272                       final LDAPConnection connection,
273                       final LDAPException exception)
274             throws LDAPException
275      {
276        if (! ResultCode.isConnectionUsable(exception.getResultCode()))
277        {
278          throw new LDAPException(ResultCode.SERVER_DOWN,
279               ERR_POOL_HEALTH_CHECK_CONN_INVALID_AFTER_EXCEPTION.get(
280                    getExceptionMessage(exception)),
281               exception);
282        }
283      }
284    
285    
286    
287      /**
288       * Retrieves a string representation of this LDAP connection pool health
289       * check.
290       *
291       * @return  A string representation of this LDAP connection pool health check.
292       */
293      @Override()
294      public final String toString()
295      {
296        final StringBuilder buffer = new StringBuilder();
297        toString(buffer);
298        return buffer.toString();
299      }
300    
301    
302    
303      /**
304       * Appends a string representation of this LDAP connection pool health check
305       * to the provided buffer.
306       *
307       * @param  buffer  The buffer to which the information should be appended.
308       */
309      public void toString(final StringBuilder buffer)
310      {
311        buffer.append("LDAPConnectionPoolHealthCheck()");
312      }
313    }