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