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