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