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