001 /*
002 * Copyright 2007-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2013 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 import com.unboundid.util.ThreadSafety;
026 import com.unboundid.util.ThreadSafetyLevel;
027
028 import static com.unboundid.ldap.sdk.LDAPMessages.*;
029 import 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)
041 public 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 }