001/*
002 * Copyright 2008-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-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.unboundidds.tasks;
022
023
024
025import java.util.ArrayList;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.Date;
029import java.util.LinkedHashMap;
030import java.util.List;
031import java.util.Map;
032
033import com.unboundid.ldap.sdk.Attribute;
034import com.unboundid.ldap.sdk.Entry;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038
039import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
040import static com.unboundid.util.Debug.*;
041
042
043
044/**
045 * This class defines a Directory Server task that can be used to request that
046 * the server terminate a client connection.
047 * <BR>
048 * <BLOCKQUOTE>
049 *   <B>NOTE:</B>  This class, and other classes within the
050 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
051 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
052 *   server products.  These classes provide support for proprietary
053 *   functionality or for external specifications that are not considered stable
054 *   or mature enough to be guaranteed to work in an interoperable way with
055 *   other types of LDAP servers.
056 * </BLOCKQUOTE>
057 * <BR>
058 * The properties that are available for use with this type of task include:
059 * <UL>
060 *   <LI>The connection ID for the client connection to be terminated.  This
061 *       is required.</LI>
062 *   <LI>A flag that indicates whether the client connection should be notified
063 *       (e.g., using a notice of disconnection unsolicited notification) before
064 *       the connection is actually terminated.</LI>
065 *   <LI>An optional message that may provide a reason for the disconnect.  If
066 *       this is provided, it will appear in the server log, and it may be
067 *       provided to the client if the client is to be notified before the
068 *       connection is closed.</LI>
069 * </UL>
070
071 */
072@NotMutable()
073@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
074public final class DisconnectClientTask
075       extends Task
076{
077  /**
078   * The fully-qualified name of the Java class that is used for the disconnect
079   * client task.
080   */
081  static final String DISCONNECT_CLIENT_TASK_CLASS =
082       "com.unboundid.directory.server.tasks.DisconnectClientTask";
083
084
085
086  /**
087   * The name of the attribute used to specify the connection ID of the client
088   * connection to terminate.
089   */
090  private static final String ATTR_CONNECTION_ID =
091       "ds-task-disconnect-connection-id";
092
093
094
095  /**
096   * The name of the attribute used to specify the disconnect message to provide
097   * to the server.
098   */
099  private static final String ATTR_DISCONNECT_MESSAGE =
100       "ds-task-disconnect-message";
101
102
103
104  /**
105   * The name of the attribute used to indicate whether to send a notice of
106   * disconnection message to the client before closing the connection.
107   */
108  private static final String ATTR_NOTIFY_CLIENT =
109       "ds-task-disconnect-notify-client";
110
111
112
113  /**
114   * The name of the object class used in disconnect client task entries.
115   */
116  private static final String OC_DISCONNECT_CLIENT_TASK = "ds-task-disconnect";
117
118
119
120  /**
121   * The task property for the connection ID.
122   */
123  private static final TaskProperty PROPERTY_CONNECTION_ID =
124       new TaskProperty(ATTR_CONNECTION_ID,
125                        INFO_DISPLAY_NAME_DISCONNECT_CONN_ID.get(),
126                        INFO_DESCRIPTION_DISCONNECT_CONN_ID.get(), Long.class,
127                        true, false, false);
128
129
130
131  /**
132   * The task property for the disconnect message.
133   */
134  private static final TaskProperty PROPERTY_DISCONNECT_MESSAGE =
135       new TaskProperty(ATTR_DISCONNECT_MESSAGE,
136                        INFO_DISPLAY_NAME_DISCONNECT_MESSAGE.get(),
137                        INFO_DESCRIPTION_DISCONNECT_MESSAGE.get(), String.class,
138                        false, false, false);
139
140
141
142  /**
143   * The task property for the notify client flag.
144   */
145  private static final TaskProperty PROPERTY_NOTIFY_CLIENT =
146       new TaskProperty(ATTR_NOTIFY_CLIENT,
147                        INFO_DISPLAY_NAME_DISCONNECT_NOTIFY.get(),
148                        INFO_DESCRIPTION_DISCONNECT_NOTIFY.get(), Boolean.class,
149                        false, false, false);
150
151
152
153  /**
154   * The serial version UID for this serializable class.
155   */
156  private static final long serialVersionUID = 6870137048384152893L;
157
158
159
160  // Indicates whether to send the client a notice of disconnection.
161  private final boolean notifyClient;
162
163  // The connection ID of the connection to disconnect.
164  private final long connectionID;
165
166  // A disconnect message to provide to the server.
167  private final String disconnectMessage;
168
169
170
171  /**
172   * Creates a new uninitialized disconnect client task instance which should
173   * only be used for obtaining general information about this task, including
174   * the task name, description, and supported properties.  Attempts to use a
175   * task created with this constructor for any other reason will likely fail.
176   */
177  public DisconnectClientTask()
178  {
179    notifyClient      = false;
180    connectionID      = -1;
181    disconnectMessage = null;
182  }
183
184
185
186
187  /**
188   * Creates a new disconnect client task with the provided information.
189   *
190   * @param  taskID             The task ID to use for this task.  If it is
191   *                            {@code null} then a UUID will be generated for
192   *                            use as the task ID.
193   * @param  connectionID       The connection ID of the client connection to
194   *                            terminate.
195   * @param  disconnectMessage  A message to provide to the server to indicate
196   *                            the reason for the disconnect.  It will be
197   *                            included in the server log, and will be provided
198   *                            to the client if a notice of disconnection is to
199   *                            be sent.  It may be {@code null} if no message
200   *                            is to be provided.
201   * @param  notifyClient       Indicates whether to send a notice of
202   *                            disconnection message to the client before
203   *                            terminating the connection.
204   */
205  public DisconnectClientTask(final String taskID, final long connectionID,
206                              final String disconnectMessage,
207                              final boolean notifyClient)
208  {
209    this(taskID, connectionID, disconnectMessage, notifyClient, null, null,
210         null, null, null);
211  }
212
213
214
215  /**
216   * Creates a new add disconnect client task with the provided information.
217   *
218   * @param  taskID                  The task ID to use for this task.  If it is
219   *                                 {@code null} then a UUID will be generated
220   *                                 for use as the task ID.
221   * @param  connectionID            The connection ID of the client connection
222   *                                 to terminate.
223   * @param  disconnectMessage       A message to provide to the server to
224   *                                 indicate the reason for the disconnect.  It
225   *                                 will be included in the server log, and
226   *                                 will be provided to the client if a notice
227   *                                 of disconnection is to be sent.  It may be
228   *                                 {@code null} if no message is to be
229   *                                 provided.
230   * @param  notifyClient            Indicates whether to send a notice of
231   *                                 disconnection message to the client before
232   *                                 terminating the connection.
233   * @param  scheduledStartTime      The time that this task should start
234   *                                 running.
235   * @param  dependencyIDs           The list of task IDs that will be required
236   *                                 to complete before this task will be
237   *                                 eligible to start.
238   * @param  failedDependencyAction  Indicates what action should be taken if
239   *                                 any of the dependencies for this task do
240   *                                 not complete successfully.
241   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
242   *                                 that should be notified when this task
243   *                                 completes.
244   * @param  notifyOnError           The list of e-mail addresses of individuals
245   *                                 that should be notified if this task does
246   *                                 not complete successfully.
247   */
248  public DisconnectClientTask(final String taskID, final long connectionID,
249              final String disconnectMessage, final boolean notifyClient,
250              final Date scheduledStartTime, final List<String> dependencyIDs,
251              final FailedDependencyAction failedDependencyAction,
252              final List<String> notifyOnCompletion,
253              final List<String> notifyOnError)
254  {
255    super(taskID, DISCONNECT_CLIENT_TASK_CLASS, scheduledStartTime,
256          dependencyIDs, failedDependencyAction, notifyOnCompletion,
257          notifyOnError);
258
259    this.connectionID      = connectionID;
260    this.disconnectMessage = disconnectMessage;
261    this.notifyClient      = notifyClient;
262  }
263
264
265
266  /**
267   * Creates a new disconnect client task from the provided entry.
268   *
269   * @param  entry  The entry to use to create this disconnect client task.
270   *
271   * @throws  TaskException  If the provided entry cannot be parsed as a
272   *                         disconnect client task entry.
273   */
274  public DisconnectClientTask(final Entry entry)
275         throws TaskException
276  {
277    super(entry);
278
279
280    // Get the connection ID.  It must be present.
281    final String idStr = entry.getAttributeValue(ATTR_CONNECTION_ID);
282    if (idStr == null)
283    {
284      throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get(
285                                   getTaskEntryDN()));
286    }
287    else
288    {
289      try
290      {
291        connectionID = Long.parseLong(idStr);
292      }
293      catch (final Exception e)
294      {
295        debugException(e);
296        throw new TaskException(ERR_DISCONNECT_TASK_CONN_ID_NOT_LONG.get(
297                                     getTaskEntryDN(), idStr),
298                                e);
299      }
300    }
301
302
303    // Get the disconnect message.  It may be absent.
304    disconnectMessage = entry.getAttributeValue(ATTR_DISCONNECT_MESSAGE);
305
306
307    // Determine whether to notify the client.  It may be absent.
308    notifyClient = parseBooleanValue(entry, ATTR_NOTIFY_CLIENT, false);
309  }
310
311
312
313  /**
314   * Creates a new disconnect client task from the provided set of task
315   * properties.
316   *
317   * @param  properties  The set of task properties and their corresponding
318   *                     values to use for the task.  It must not be
319   *                     {@code null}.
320   *
321   * @throws  TaskException  If the provided set of properties cannot be used to
322   *                         create a valid disconnect client task.
323   */
324  public DisconnectClientTask(final Map<TaskProperty,List<Object>> properties)
325         throws TaskException
326  {
327    super(DISCONNECT_CLIENT_TASK_CLASS, properties);
328
329    boolean notify = false;
330    Long    connID = null;
331    String  msg    = null;
332
333
334    for (final Map.Entry<TaskProperty,List<Object>> entry :
335         properties.entrySet())
336    {
337      final TaskProperty p = entry.getKey();
338      final String attrName = p.getAttributeName();
339      final List<Object> values = entry.getValue();
340
341      if (attrName.equalsIgnoreCase(ATTR_CONNECTION_ID))
342      {
343        connID = parseLong(p, values, connID);
344      }
345      else if (attrName.equalsIgnoreCase(ATTR_DISCONNECT_MESSAGE))
346      {
347        msg = parseString(p, values, msg);
348      }
349      else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_CLIENT))
350      {
351        notify = parseBoolean(p, values, notify);
352      }
353    }
354
355    if (connID == null)
356    {
357      throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get(
358                                   getTaskEntryDN()));
359    }
360
361    connectionID      = connID;
362    disconnectMessage = msg;
363    notifyClient      = notify;
364  }
365
366
367
368  /**
369   * {@inheritDoc}
370   */
371  @Override()
372  public String getTaskName()
373  {
374    return INFO_TASK_NAME_DISCONNECT_CLIENT.get();
375  }
376
377
378
379  /**
380   * {@inheritDoc}
381   */
382  @Override()
383  public String getTaskDescription()
384  {
385    return INFO_TASK_DESCRIPTION_DISCONNECT_CLIENT.get();
386  }
387
388
389
390  /**
391   * Retrieves the connection ID of the client connection to disconnect.
392   *
393   * @return  The connection ID of the client connection to disconnect.
394   */
395  public long getConnectionID()
396  {
397    return connectionID;
398  }
399
400
401
402  /**
403   * Retrieves the disconnect message to provide to the server, and potentially
404   * to the client.
405   *
406   * @return  The disconnect message, or {@code null} if no message is to be
407   *          provided.
408   */
409  public String getDisconnectMessage()
410  {
411    return disconnectMessage;
412  }
413
414
415
416  /**
417   * Indicates whether to send a notice of disconnection message to the client
418   * before terminating the connection.
419   *
420   * @return  {@code true} if the server should send a notice of disconnection
421   *          to the client, or {@code false} if it should terminate the
422   *          connection without warning.
423   */
424  public boolean notifyClient()
425  {
426    return notifyClient;
427  }
428
429
430
431  /**
432   * {@inheritDoc}
433   */
434  @Override()
435  protected List<String> getAdditionalObjectClasses()
436  {
437    return Arrays.asList(OC_DISCONNECT_CLIENT_TASK);
438  }
439
440
441
442  /**
443   * {@inheritDoc}
444   */
445  @Override()
446  protected List<Attribute> getAdditionalAttributes()
447  {
448    final ArrayList<Attribute> attrs = new ArrayList<Attribute>(3);
449
450    attrs.add(new Attribute(ATTR_CONNECTION_ID, String.valueOf(connectionID)));
451    attrs.add(new Attribute(ATTR_NOTIFY_CLIENT, String.valueOf(notifyClient)));
452
453    if (disconnectMessage != null)
454    {
455      attrs.add(new Attribute(ATTR_DISCONNECT_MESSAGE, disconnectMessage));
456    }
457
458    return attrs;
459  }
460
461
462
463  /**
464   * {@inheritDoc}
465   */
466  @Override()
467  public List<TaskProperty> getTaskSpecificProperties()
468  {
469    final List<TaskProperty> propList = Arrays.asList(
470         PROPERTY_CONNECTION_ID,
471         PROPERTY_DISCONNECT_MESSAGE,
472         PROPERTY_NOTIFY_CLIENT);
473
474    return Collections.unmodifiableList(propList);
475  }
476
477
478
479  /**
480   * {@inheritDoc}
481   */
482  @Override()
483  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
484  {
485    final LinkedHashMap<TaskProperty,List<Object>> props =
486         new LinkedHashMap<TaskProperty,List<Object>>();
487
488    props.put(PROPERTY_CONNECTION_ID,
489              Collections.<Object>unmodifiableList(Arrays.asList(
490                   connectionID)));
491
492    if (disconnectMessage == null)
493    {
494      props.put(PROPERTY_DISCONNECT_MESSAGE, Collections.emptyList());
495    }
496    else
497    {
498      props.put(PROPERTY_DISCONNECT_MESSAGE,
499                Collections.<Object>unmodifiableList(Arrays.asList(
500                     disconnectMessage)));
501    }
502
503    props.put(PROPERTY_NOTIFY_CLIENT,
504              Collections.<Object>unmodifiableList(Arrays.asList(
505                   notifyClient)));
506
507    props.putAll(super.getTaskPropertyValues());
508    return Collections.unmodifiableMap(props);
509  }
510}