001/* 002 * Copyright 2007-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-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) 2007-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.NotNull; 041import com.unboundid.util.Nullable; 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 enum defines a set of disconnect types that may be used to provide 052 * general information about the reason that an {@link LDAPConnection} was 053 * disconnected. Note that additional disconnect types may be added in the 054 * future, so any decision made based on a disconnect type should account for 055 * the possibility of previously-undefined disconnect types. 056 */ 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public enum DisconnectType 059{ 060 /** 061 * The connection was closed as a result of an unbind request sent by the 062 * client. 063 */ 064 UNBIND(INFO_DISCONNECT_TYPE_UNBIND.get(), ResultCode.LOCAL_ERROR), 065 066 067 068 /** 069 * The connection was closed at the request of the client, but without first 070 * sending an unbind request. 071 */ 072 CLOSED_WITHOUT_UNBIND(INFO_DISCONNECT_TYPE_CLOSED_WITHOUT_UNBIND.get(), 073 ResultCode.LOCAL_ERROR), 074 075 076 077 /** 078 * The connection was closed because a bind performed as part of the 079 * creation did not complete successfully. 080 */ 081 BIND_FAILED(INFO_DISCONNECT_TYPE_BIND_FAILED.get(), 082 ResultCode.CONNECT_ERROR), 083 084 085 086 /** 087 * The connection was closed because it is going to be re-established. 088 */ 089 RECONNECT(INFO_DISCONNECT_TYPE_RECONNECT.get(), ResultCode.SERVER_DOWN), 090 091 092 093 /** 094 * The connection was closed because it had been a temporary connection 095 * created for following a referral and was no longer needed. 096 */ 097 REFERRAL(INFO_DISCONNECT_TYPE_REFERRAL.get(), ResultCode.LOCAL_ERROR), 098 099 100 101 /** 102 * The connection was closed by the server, and a notice of disconnection 103 * unsolicited notification was provided. 104 */ 105 SERVER_CLOSED_WITH_NOTICE( 106 INFO_DISCONNECT_TYPE_SERVER_CLOSED_WITH_NOTICE.get(), 107 ResultCode.SERVER_DOWN), 108 109 110 111 /** 112 * The connection was closed by the server without a notice of disconnection. 113 */ 114 SERVER_CLOSED_WITHOUT_NOTICE( 115 INFO_DISCONNECT_TYPE_SERVER_CLOSED_WITHOUT_NOTICE.get(), 116 ResultCode.SERVER_DOWN), 117 118 119 120 /** 121 * The connection was closed because an I/O problem was encountered while 122 * trying to communicate with the server. 123 */ 124 IO_ERROR(INFO_DISCONNECT_TYPE_IO_ERROR.get(), ResultCode.SERVER_DOWN), 125 126 127 128 /** 129 * The connection was closed because an error occurred while trying to decode 130 * data from the server. 131 */ 132 DECODE_ERROR(INFO_DISCONNECT_TYPE_DECODE_ERROR.get(), 133 ResultCode.DECODING_ERROR), 134 135 136 137 /** 138 * The connection was closed because an unexpected error occurred within the 139 * LDAP SDK. 140 */ 141 LOCAL_ERROR(INFO_DISCONNECT_TYPE_LOCAL_ERROR.get(), ResultCode.LOCAL_ERROR), 142 143 144 145 /** 146 * The connection was closed because a problem was encountered while 147 * negotiating a security layer with the server. 148 */ 149 SECURITY_PROBLEM(INFO_DISCONNECT_TYPE_SECURITY_PROBLEM.get(), 150 ResultCode.LOCAL_ERROR), 151 152 153 154 /** 155 * The connection was closed because it was part of a connection pool that 156 * was closed. 157 */ 158 POOL_CLOSED(INFO_DISCONNECT_TYPE_POOL_CLOSED.get(), ResultCode.LOCAL_ERROR), 159 160 161 162 /** 163 * The connection was closed because it was part of a connection pool that 164 * was being initialized and a failure occurred while attempting to create 165 * another connection as part of the pool. 166 */ 167 POOL_CREATION_FAILURE(INFO_DISCONNECT_TYPE_POOL_CREATION_FAILURE.get(), 168 ResultCode.CONNECT_ERROR), 169 170 171 172 /** 173 * The connection was closed because it was part of a connection pool and had 174 * been classified as defunct. 175 */ 176 POOLED_CONNECTION_DEFUNCT( 177 INFO_DISCONNECT_TYPE_POOLED_CONNECTION_DEFUNCT.get(), 178 ResultCode.SERVER_DOWN), 179 180 181 182 /** 183 * The connection was closed because it was part of a connection pool and the 184 * connection had been established for longer than the maximum connection 185 * age for the pool. 186 */ 187 POOLED_CONNECTION_EXPIRED( 188 INFO_DISCONNECT_TYPE_POOLED_CONNECTION_EXPIRED.get(), 189 ResultCode.LOCAL_ERROR), 190 191 192 193 /** 194 * The connection was closed because it was part of a connection pool and was 195 * no longer needed. 196 */ 197 POOLED_CONNECTION_UNNEEDED( 198 INFO_DISCONNECT_TYPE_POOLED_CONNECTION_UNNEEDED.get(), 199 ResultCode.LOCAL_ERROR), 200 201 202 203 /** 204 * The reason for the disconnect is not known. This generally indicates a 205 * problem with inappropriate instrumentation in the LDAP SDK. 206 */ 207 UNKNOWN(INFO_DISCONNECT_TYPE_UNKNOWN.get(), ResultCode.LOCAL_ERROR), 208 209 210 211 /** 212 * The connection was closed by a finalizer in the LDAP SDK, which indicates 213 * that it was not properly closed by the application that had been using 214 * it. 215 */ 216 CLOSED_BY_FINALIZER(INFO_DISCONNECT_TYPE_CLOSED_BY_FINALIZER.get(), 217 ResultCode.LOCAL_ERROR), 218 219 220 221 /** 222 * The connection was closed for a reason that does not fit any other 223 * defined disconnect type. 224 */ 225 OTHER(INFO_DISCONNECT_TYPE_OTHER.get(), ResultCode.LOCAL_ERROR); 226 227 228 229 // The result code most closely associated with this disconnect type. 230 @NotNull private final ResultCode resultCode; 231 232 // A description for this disconnect type. 233 @NotNull private final String description; 234 235 236 237 /** 238 * Creates a new disconnect type with the specified description. 239 * 240 * @param description The description for this disconnect type. 241 * @param resultCode The result code most closely associated with this 242 * disconnect type. 243 */ 244 DisconnectType(@NotNull final String description, 245 @NotNull final ResultCode resultCode) 246 { 247 this.description = description; 248 this.resultCode = resultCode; 249 } 250 251 252 253 /** 254 * Retrieves the description for this disconnect type. 255 * 256 * @return The description for this disconnect type. 257 */ 258 @NotNull() 259 public String getDescription() 260 { 261 return description; 262 } 263 264 265 266 /** 267 * Retrieves the result code most closely associated with this disconnect 268 * type. 269 * 270 * @return The result code most closely associated with this disconnect type. 271 */ 272 @NotNull() 273 public ResultCode getResultCode() 274 { 275 return resultCode; 276 } 277 278 279 280 /** 281 * Retrieves the disconnect type with the specified name. 282 * 283 * @param name The name of the disconnect type to retrieve. 284 * 285 * @return The requested change type, or {@code null} if no such 286 * disconnect type is defined. 287 */ 288 @Nullable() 289 public static DisconnectType forName(@NotNull final String name) 290 { 291 switch (StaticUtils.toLowerCase(name)) 292 { 293 case "unbind": 294 return UNBIND; 295 case "closedwithoutunbind": 296 case "closed-without-unbind": 297 case "closed_without_unbind": 298 return CLOSED_WITHOUT_UNBIND; 299 case "bindfailed": 300 case "bind-failed": 301 case "bind_failed": 302 return BIND_FAILED; 303 case "reconnect": 304 return RECONNECT; 305 case "referral": 306 return REFERRAL; 307 case "serverclosedwithnotice": 308 case "server-closed-with-notice": 309 case "server_closed_with_notice": 310 return SERVER_CLOSED_WITH_NOTICE; 311 case "serverclosedwithoutnotice": 312 case "server-closed-without-notice": 313 case "server_closed_without_notice": 314 return SERVER_CLOSED_WITHOUT_NOTICE; 315 case "ioerror": 316 case "io-error": 317 case "io_error": 318 return IO_ERROR; 319 case "decodeerror": 320 case "decode-error": 321 case "decode_error": 322 return DECODE_ERROR; 323 case "localerror": 324 case "local-error": 325 case "local_error": 326 return LOCAL_ERROR; 327 case "securityproblem": 328 case "security-problem": 329 case "security_problem": 330 return SECURITY_PROBLEM; 331 case "poolclosed": 332 case "pool-closed": 333 case "pool_closed": 334 return POOL_CLOSED; 335 case "poolcreationfailure": 336 case "pool-creation-failure": 337 case "pool_creation_failure": 338 return POOL_CREATION_FAILURE; 339 case "pooledconnectiondefunct": 340 case "pooled-connection-defunct": 341 case "pooled_connection_defunct": 342 return POOLED_CONNECTION_DEFUNCT; 343 case "pooledconnectionexpired": 344 case "pooled-connection-expired": 345 case "pooled_connection_expired": 346 return POOLED_CONNECTION_EXPIRED; 347 case "pooledconnectionunneeded": 348 case "pooled-connection-unneeded": 349 case "pooled_connection_unneeded": 350 return POOLED_CONNECTION_UNNEEDED; 351 case "unknown": 352 return UNKNOWN; 353 case "closedbyfinalizer": 354 case "closed-by-finalizer": 355 case "closed_by_finalizer": 356 return CLOSED_BY_FINALIZER; 357 case "other": 358 return OTHER; 359 default: 360 return null; 361 } 362 } 363 364 365 366 /** 367 * Indicates whether the provided disconnect type is likely one that is 368 * expected in some way. This includes the following: 369 * <UL> 370 * <LI>Connections closed by the application.</LI> 371 * <LI>Connections which are managed as part of a connection pool.</LI> 372 * <LI>Temporary connections created for following a referral.</LI> 373 * <LI>Connections which are being closed by the SDK so they can be 374 * re-established.</LI> 375 * <LI>Connections that were not properly closed by the application but are 376 * no longer in use and are being closed by a finalizer.</LI> 377 * </UL> 378 * 379 * @param disconnectType The disconnect type for which to make the 380 * determination. 381 * 382 * @return {@code true} if the connection is one that can be classified as 383 * expected and there is likely nothing that a disconnect handler 384 * needs to do to handle it, or {@code false} if not. 385 */ 386 public static boolean isExpected(@NotNull final DisconnectType disconnectType) 387 { 388 switch (disconnectType) 389 { 390 case UNBIND: 391 case CLOSED_WITHOUT_UNBIND: 392 case RECONNECT: 393 case REFERRAL: 394 case POOL_CLOSED: 395 case POOLED_CONNECTION_DEFUNCT: 396 case POOLED_CONNECTION_EXPIRED: 397 case POOLED_CONNECTION_UNNEEDED: 398 case CLOSED_BY_FINALIZER: 399 return true; 400 default: 401 return false; 402 } 403 } 404 405 406 407 /** 408 * Retrieves a string representation for this disconnect type. 409 * 410 * @return A string representation for this disconnect type. 411 */ 412 @Override() 413 @NotNull() 414 public String toString() 415 { 416 final StringBuilder buffer = new StringBuilder(); 417 toString(buffer); 418 return buffer.toString(); 419 } 420 421 422 423 /** 424 * Appends a string representation of this disconnect type to the provided 425 * buffer. 426 * 427 * @param buffer The buffer to which the string representation should be 428 * appended. 429 */ 430 public void toString(@NotNull final StringBuilder buffer) 431 { 432 buffer.append("DisconnectType(name='"); 433 buffer.append(name()); 434 buffer.append("', resultCode='"); 435 buffer.append(resultCode); 436 buffer.append("', description='"); 437 buffer.append(description); 438 buffer.append("')"); 439 } 440}