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