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