001/* 002 * Copyright 2009-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.sdk; 022 023 024 025import com.unboundid.util.Extensible; 026import com.unboundid.util.StaticUtils; 027import com.unboundid.util.ThreadSafety; 028import com.unboundid.util.ThreadSafetyLevel; 029 030import static com.unboundid.ldap.sdk.LDAPMessages.*; 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) 081public 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 * Performs any processing that may be appropriate on an ongoing basis for the 258 * connection pool that is not related to the pool itself rather than any 259 * individual connection. This method will be invoked by the pool's 260 * {@link LDAPConnectionPoolHealthCheckThread} at an interval specified by the 261 * pool's {@link AbstractConnectionPool#getHealthCheckIntervalMillis()} 262 * method. This method will be invoked after all other periodic processing 263 * (for example, after calling {@link #ensureConnectionValidForContinuedUse} 264 * on each available connection, if appropriate for the pool implementation) 265 * has been performed during the interval. 266 * 267 * @param pool The connection pool on which to perform maintenance. 268 */ 269 public void performPoolMaintenance(final AbstractConnectionPool pool) 270 { 271 // No processing is performed in this default implementation. 272 } 273 274 275 276 /** 277 * Indicates whether the provided connection may still be considered valid 278 * after an attempt to process an operation yielded the given exception. This 279 * method will be invoked by the 280 * {@link LDAPConnectionPool#releaseConnectionAfterException} method, and it 281 * may also be manually invoked by external callers if an exception is 282 * encountered while processing an operation on a connection checked out from 283 * the pool. It may make a determination based solely on the provided 284 * exception, or it may also attempt to use the provided connection to further 285 * test its validity. This method should return normally if the connection is 286 * believed to be valid, or should throw an {@code LDAPException} if a problem 287 * is detected. 288 * 289 * @param connection The connection to be examined. 290 * @param exception The exception that was caught while processing an 291 * operation on the connection. 292 * 293 * @throws LDAPException If a problem is detected that suggests that the 294 * provided connection is not suitable for use. 295 */ 296 public void ensureConnectionValidAfterException( 297 final LDAPConnection connection, 298 final LDAPException exception) 299 throws LDAPException 300 { 301 if (! ResultCode.isConnectionUsable(exception.getResultCode())) 302 { 303 throw new LDAPException(ResultCode.SERVER_DOWN, 304 ERR_POOL_HEALTH_CHECK_CONN_INVALID_AFTER_EXCEPTION.get( 305 StaticUtils.getExceptionMessage(exception)), 306 exception); 307 } 308 } 309 310 311 312 /** 313 * Retrieves a string representation of this LDAP connection pool health 314 * check. 315 * 316 * @return A string representation of this LDAP connection pool health check. 317 */ 318 @Override() 319 public final String toString() 320 { 321 final StringBuilder buffer = new StringBuilder(); 322 toString(buffer); 323 return buffer.toString(); 324 } 325 326 327 328 /** 329 * Appends a string representation of this LDAP connection pool health check 330 * to the provided buffer. 331 * 332 * @param buffer The buffer to which the information should be appended. 333 */ 334 public void toString(final StringBuilder buffer) 335 { 336 buffer.append("LDAPConnectionPoolHealthCheck()"); 337 } 338}