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 }