001/* 002 * Copyright 2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 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) 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 java.util.concurrent.TimeUnit; 041import java.util.concurrent.atomic.LongAdder; 042 043import com.unboundid.util.NotMutable; 044import com.unboundid.util.NotNull; 045import com.unboundid.util.ThreadSafety; 046import com.unboundid.util.ThreadSafetyLevel; 047import com.unboundid.util.Validator; 048 049import static com.unboundid.ldap.sdk.LDAPMessages.*; 050 051 052 053/** 054 * This class provides an implementation of an LDAP connection pool health check 055 * that will cause the associated connection pool to consider a connection 056 * invalid after it has remained idle (as determined using the 057 * {@link LDAPConnection#getLastCommunicationTime()} method) for more than a 058 * specified length of time. This is primarily useful in cases where the 059 * associated directory servers (or some intermediate networking equipment) may 060 * terminate connections that have remained idle for too long. 061 * <BR><BR> 062 * Note that in connection pools that may contain connections across multiple 063 * servers, you should probably use the 064 * {@link LDAPConnectionPool#setMaxConnectionAgeMillis(long)} method instead of 065 * this health check to ensure that connections are automatically refreshed 066 * after a specified duration, regardless of whether they have been idle. 067 * Setting a maximum connection age will help ensure that connections in the 068 * pool will return to a relatively balanced state after a failure has caused 069 * connections to migrate away from one or more of those servers. 070 * <BR><BR> 071 * Also note that as an alternative to this health check, you may wish to 072 * consider a health check that actually attempts to communicate with the 073 * destination server over LDAP (e.g., the 074 * {@link GetEntryLDAPConnectionPoolHealthCheck}). Not only will those types of 075 * health checks do a better job of ensuring that the connection is still valid 076 * (and that the server to which it is established is responsive), but the 077 * communication that they perform will also prevent them from being considered 078 * idle. 079 * 080 * @see LDAPConnectionPool 081 * @see LDAPConnectionPoolHealthCheck 082 */ 083@NotMutable() 084@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 085public final class MaximumIdleDurationLDAPConnectionPoolHealthCheck 086 extends LDAPConnectionPoolHealthCheck 087{ 088 // A counter that will be incremented any time an idle connection is 089 // identified. 090 @NotNull private final LongAdder idleConnectionCounter; 091 092 // The maximum length of time in milliseconds that connections will be allowed 093 // to remain idle before they will be replaced by the associated connection 094 // pool. 095 private final long maximumIdleDurationMillis; 096 097 098 099 /** 100 * Creates a new instance of this health check that will use the specified 101 * maximum idle duration. 102 * 103 * @param maximumIdleDurationValue 104 * The value that specifies the maximum length of time, in 105 * conjunction with the specified time unit, that connections 106 * will be allowed to remain idle before they will be replaced 107 * by the associated connection pool. This value must be greater 108 * than zero. 109 * @param maximumIdleDurationTimeUnit 110 * The time unit to use when interpreting the provided maximum 111 * idle duration value. It must not be {@code null}. 112 */ 113 public MaximumIdleDurationLDAPConnectionPoolHealthCheck( 114 final long maximumIdleDurationValue, 115 @NotNull final TimeUnit maximumIdleDurationTimeUnit) 116 { 117 this(maximumIdleDurationTimeUnit.toMillis(maximumIdleDurationValue)); 118 } 119 120 121 122 /** 123 * Creates a new instance of this health check that will use the specified 124 * maximum idle duration. 125 * 126 * @param maximumIdleDurationMillis 127 * The maximum length of time in milliseconds that connections 128 * will be allowed to remain idle before they will be replaced by 129 * the associated connection pool. This value must be greater 130 * than zero. 131 */ 132 public MaximumIdleDurationLDAPConnectionPoolHealthCheck( 133 final long maximumIdleDurationMillis) 134 { 135 Validator.ensureTrue((maximumIdleDurationMillis > 0L), 136 "MaximumIdleDurationLDAPConnectionPoolHealthCheck." + 137 "maximumIdleDurationMillis must be greater than zero."); 138 139 this.maximumIdleDurationMillis = maximumIdleDurationMillis; 140 141 idleConnectionCounter = new LongAdder(); 142 } 143 144 145 146 /** 147 * Retrieves the maximum length of time in milliseconds that connections will 148 * be allowed to remain idle before they will be replaced by the associated 149 * connection pool. 150 * 151 * @return The maximum length of time in milliseconds that connections will 152 * be allowed to remain idle before they will be replaced by the 153 * associated connection pool. 154 */ 155 public long getMaximumIdleDurationMillis() 156 { 157 return maximumIdleDurationMillis; 158 } 159 160 161 162 /** 163 * Retrieves the number of pooled connections that this health check has 164 * considered invalid because of their idle duration. 165 * 166 * @return The number of pooled connections that this health check has 167 * considered invalid because of their idle duration. 168 */ 169 public long getIdleConnectionCount() 170 { 171 return idleConnectionCounter.longValue(); 172 } 173 174 175 176 /** 177 * {@inheritDoc} 178 */ 179 @Override() 180 public void ensureConnectionValidForContinuedUse( 181 @NotNull final LDAPConnection connection) 182 throws LDAPException 183 { 184 final long currentTime = System.currentTimeMillis(); 185 final long lastCommunicationTime = connection.getLastCommunicationTime(); 186 final long idleDurationMillis = currentTime - lastCommunicationTime; 187 188 if (idleDurationMillis > maximumIdleDurationMillis) 189 { 190 idleConnectionCounter.increment(); 191 throw new LDAPException(ResultCode.TIMEOUT, 192 ERR_IDLE_HEALTH_CHECK_CONNECTION_IDLE.get(idleDurationMillis, 193 maximumIdleDurationMillis)); 194 } 195 } 196 197 198 199 /** 200 * Appends a string representation of this LDAP connection pool health check 201 * to the provided buffer. 202 * 203 * @param buffer The buffer to which the information should be appended. 204 */ 205 public void toString(@NotNull final StringBuilder buffer) 206 { 207 buffer.append("MaximumIdleDurationLDAPConnectionPoolHealthCheck(" + 208 "maximumIdleDurationMillis="); 209 buffer.append(maximumIdleDurationMillis); 210 buffer.append(')'); 211 } 212}