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