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.Debug;
036import com.unboundid.util.NotMutable;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039
040import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*;
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
052 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
053 *   for proprietary functionality or for external specifications that are not
054 *   considered stable or mature enough to be guaranteed to work in an
055 *   interoperable way with 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   * Creates a new disconnect client task with the provided information.
188   *
189   * @param  taskID             The task ID to use for this task.  If it is
190   *                            {@code null} then a UUID will be generated for
191   *                            use as the task ID.
192   * @param  connectionID       The connection ID of the client connection to
193   *                            terminate.
194   * @param  disconnectMessage  A message to provide to the server to indicate
195   *                            the reason for the disconnect.  It will be
196   *                            included in the server log, and will be provided
197   *                            to the client if a notice of disconnection is to
198   *                            be sent.  It may be {@code null} if no message
199   *                            is to be provided.
200   * @param  notifyClient       Indicates whether to send a notice of
201   *                            disconnection message to the client before
202   *                            terminating the connection.
203   */
204  public DisconnectClientTask(final String taskID, final long connectionID,
205                              final String disconnectMessage,
206                              final boolean notifyClient)
207  {
208    this(taskID, connectionID, disconnectMessage, notifyClient, null, null,
209         null, null, null);
210  }
211
212
213
214  /**
215   * Creates a new add disconnect client task with the provided information.
216   *
217   * @param  taskID                  The task ID to use for this task.  If it is
218   *                                 {@code null} then a UUID will be generated
219   *                                 for use as the task ID.
220   * @param  connectionID            The connection ID of the client connection
221   *                                 to terminate.
222   * @param  disconnectMessage       A message to provide to the server to
223   *                                 indicate the reason for the disconnect.  It
224   *                                 will be included in the server log, and
225   *                                 will be provided to the client if a notice
226   *                                 of disconnection is to be sent.  It may be
227   *                                 {@code null} if no message is to be
228   *                                 provided.
229   * @param  notifyClient            Indicates whether to send a notice of
230   *                                 disconnection message to the client before
231   *                                 terminating the connection.
232   * @param  scheduledStartTime      The time that this task should start
233   *                                 running.
234   * @param  dependencyIDs           The list of task IDs that will be required
235   *                                 to complete before this task will be
236   *                                 eligible to start.
237   * @param  failedDependencyAction  Indicates what action should be taken if
238   *                                 any of the dependencies for this task do
239   *                                 not complete successfully.
240   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
241   *                                 that should be notified when this task
242   *                                 completes.
243   * @param  notifyOnError           The list of e-mail addresses of individuals
244   *                                 that should be notified if this task does
245   *                                 not complete successfully.
246   */
247  public DisconnectClientTask(final String taskID, final long connectionID,
248              final String disconnectMessage, final boolean notifyClient,
249              final Date scheduledStartTime, final List<String> dependencyIDs,
250              final FailedDependencyAction failedDependencyAction,
251              final List<String> notifyOnCompletion,
252              final List<String> notifyOnError)
253  {
254    this(taskID, connectionID, disconnectMessage, notifyClient,
255         scheduledStartTime, dependencyIDs, failedDependencyAction, null,
256         notifyOnCompletion, null, notifyOnError, null, null, null);
257  }
258
259
260
261  /**
262   * Creates a new add disconnect client task with the provided information.
263   *
264   * @param  taskID                  The task ID to use for this task.  If it is
265   *                                 {@code null} then a UUID will be generated
266   *                                 for use as the task ID.
267   * @param  connectionID            The connection ID of the client connection
268   *                                 to terminate.
269   * @param  disconnectMessage       A message to provide to the server to
270   *                                 indicate the reason for the disconnect.  It
271   *                                 will be included in the server log, and
272   *                                 will be provided to the client if a notice
273   *                                 of disconnection is to be sent.  It may be
274   *                                 {@code null} if no message is to be
275   *                                 provided.
276   * @param  notifyClient            Indicates whether to send a notice of
277   *                                 disconnection message to the client before
278   *                                 terminating the connection.
279   * @param  scheduledStartTime      The time that this task should start
280   *                                 running.
281   * @param  dependencyIDs           The list of task IDs that will be required
282   *                                 to complete before this task will be
283   *                                 eligible to start.
284   * @param  failedDependencyAction  Indicates what action should be taken if
285   *                                 any of the dependencies for this task do
286   *                                 not complete successfully.
287   * @param  notifyOnStart           The list of e-mail addresses of individuals
288   *                                 that should be notified when this task
289   *                                 starts running.
290   * @param  notifyOnCompletion      The list of e-mail addresses of individuals
291   *                                 that should be notified when this task
292   *                                 completes.
293   * @param  notifyOnSuccess         The list of e-mail addresses of individuals
294   *                                 that should be notified if this task
295   *                                 completes successfully.
296   * @param  notifyOnError           The list of e-mail addresses of individuals
297   *                                 that should be notified if this task does
298   *                                 not complete successfully.
299   * @param  alertOnStart            Indicates whether the server should send an
300   *                                 alert notification when this task starts.
301   * @param  alertOnSuccess          Indicates whether the server should send an
302   *                                 alert notification if this task completes
303   *                                 successfully.
304   * @param  alertOnError            Indicates whether the server should send an
305   *                                 alert notification if this task fails to
306   *                                 complete successfully.
307   */
308  public DisconnectClientTask(final String taskID, final long connectionID,
309              final String disconnectMessage, final boolean notifyClient,
310              final Date scheduledStartTime, final List<String> dependencyIDs,
311              final FailedDependencyAction failedDependencyAction,
312              final List<String> notifyOnStart,
313              final List<String> notifyOnCompletion,
314              final List<String> notifyOnSuccess,
315              final List<String> notifyOnError, final Boolean alertOnStart,
316              final Boolean alertOnSuccess, final Boolean alertOnError)
317  {
318    super(taskID, DISCONNECT_CLIENT_TASK_CLASS, scheduledStartTime,
319          dependencyIDs, failedDependencyAction, notifyOnStart,
320         notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart,
321         alertOnSuccess, alertOnError);
322
323    this.connectionID      = connectionID;
324    this.disconnectMessage = disconnectMessage;
325    this.notifyClient      = notifyClient;
326  }
327
328
329
330  /**
331   * Creates a new disconnect client task from the provided entry.
332   *
333   * @param  entry  The entry to use to create this disconnect client task.
334   *
335   * @throws  TaskException  If the provided entry cannot be parsed as a
336   *                         disconnect client task entry.
337   */
338  public DisconnectClientTask(final Entry entry)
339         throws TaskException
340  {
341    super(entry);
342
343
344    // Get the connection ID.  It must be present.
345    final String idStr = entry.getAttributeValue(ATTR_CONNECTION_ID);
346    if (idStr == null)
347    {
348      throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get(
349                                   getTaskEntryDN()));
350    }
351    else
352    {
353      try
354      {
355        connectionID = Long.parseLong(idStr);
356      }
357      catch (final Exception e)
358      {
359        Debug.debugException(e);
360        throw new TaskException(ERR_DISCONNECT_TASK_CONN_ID_NOT_LONG.get(
361                                     getTaskEntryDN(), idStr),
362                                e);
363      }
364    }
365
366
367    // Get the disconnect message.  It may be absent.
368    disconnectMessage = entry.getAttributeValue(ATTR_DISCONNECT_MESSAGE);
369
370
371    // Determine whether to notify the client.  It may be absent.
372    notifyClient = parseBooleanValue(entry, ATTR_NOTIFY_CLIENT, false);
373  }
374
375
376
377  /**
378   * Creates a new disconnect client task from the provided set of task
379   * properties.
380   *
381   * @param  properties  The set of task properties and their corresponding
382   *                     values to use for the task.  It must not be
383   *                     {@code null}.
384   *
385   * @throws  TaskException  If the provided set of properties cannot be used to
386   *                         create a valid disconnect client task.
387   */
388  public DisconnectClientTask(final Map<TaskProperty,List<Object>> properties)
389         throws TaskException
390  {
391    super(DISCONNECT_CLIENT_TASK_CLASS, properties);
392
393    boolean notify = false;
394    Long    connID = null;
395    String  msg    = null;
396
397
398    for (final Map.Entry<TaskProperty,List<Object>> entry :
399         properties.entrySet())
400    {
401      final TaskProperty p = entry.getKey();
402      final String attrName = p.getAttributeName();
403      final List<Object> values = entry.getValue();
404
405      if (attrName.equalsIgnoreCase(ATTR_CONNECTION_ID))
406      {
407        connID = parseLong(p, values, connID);
408      }
409      else if (attrName.equalsIgnoreCase(ATTR_DISCONNECT_MESSAGE))
410      {
411        msg = parseString(p, values, msg);
412      }
413      else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_CLIENT))
414      {
415        notify = parseBoolean(p, values, notify);
416      }
417    }
418
419    if (connID == null)
420    {
421      throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get(
422                                   getTaskEntryDN()));
423    }
424
425    connectionID      = connID;
426    disconnectMessage = msg;
427    notifyClient      = notify;
428  }
429
430
431
432  /**
433   * {@inheritDoc}
434   */
435  @Override()
436  public String getTaskName()
437  {
438    return INFO_TASK_NAME_DISCONNECT_CLIENT.get();
439  }
440
441
442
443  /**
444   * {@inheritDoc}
445   */
446  @Override()
447  public String getTaskDescription()
448  {
449    return INFO_TASK_DESCRIPTION_DISCONNECT_CLIENT.get();
450  }
451
452
453
454  /**
455   * Retrieves the connection ID of the client connection to disconnect.
456   *
457   * @return  The connection ID of the client connection to disconnect.
458   */
459  public long getConnectionID()
460  {
461    return connectionID;
462  }
463
464
465
466  /**
467   * Retrieves the disconnect message to provide to the server, and potentially
468   * to the client.
469   *
470   * @return  The disconnect message, or {@code null} if no message is to be
471   *          provided.
472   */
473  public String getDisconnectMessage()
474  {
475    return disconnectMessage;
476  }
477
478
479
480  /**
481   * Indicates whether to send a notice of disconnection message to the client
482   * before terminating the connection.
483   *
484   * @return  {@code true} if the server should send a notice of disconnection
485   *          to the client, or {@code false} if it should terminate the
486   *          connection without warning.
487   */
488  public boolean notifyClient()
489  {
490    return notifyClient;
491  }
492
493
494
495  /**
496   * {@inheritDoc}
497   */
498  @Override()
499  protected List<String> getAdditionalObjectClasses()
500  {
501    return Collections.singletonList(OC_DISCONNECT_CLIENT_TASK);
502  }
503
504
505
506  /**
507   * {@inheritDoc}
508   */
509  @Override()
510  protected List<Attribute> getAdditionalAttributes()
511  {
512    final ArrayList<Attribute> attrs = new ArrayList<>(3);
513
514    attrs.add(new Attribute(ATTR_CONNECTION_ID, String.valueOf(connectionID)));
515    attrs.add(new Attribute(ATTR_NOTIFY_CLIENT, String.valueOf(notifyClient)));
516
517    if (disconnectMessage != null)
518    {
519      attrs.add(new Attribute(ATTR_DISCONNECT_MESSAGE, disconnectMessage));
520    }
521
522    return attrs;
523  }
524
525
526
527  /**
528   * {@inheritDoc}
529   */
530  @Override()
531  public List<TaskProperty> getTaskSpecificProperties()
532  {
533    final List<TaskProperty> propList = Arrays.asList(
534         PROPERTY_CONNECTION_ID,
535         PROPERTY_DISCONNECT_MESSAGE,
536         PROPERTY_NOTIFY_CLIENT);
537
538    return Collections.unmodifiableList(propList);
539  }
540
541
542
543  /**
544   * {@inheritDoc}
545   */
546  @Override()
547  public Map<TaskProperty,List<Object>> getTaskPropertyValues()
548  {
549    final LinkedHashMap<TaskProperty,List<Object>> props =
550         new LinkedHashMap<>(10);
551
552    props.put(PROPERTY_CONNECTION_ID,
553              Collections.<Object>singletonList(connectionID));
554
555    if (disconnectMessage == null)
556    {
557      props.put(PROPERTY_DISCONNECT_MESSAGE, Collections.emptyList());
558    }
559    else
560    {
561      props.put(PROPERTY_DISCONNECT_MESSAGE,
562                Collections.<Object>singletonList(disconnectMessage));
563    }
564
565    props.put(PROPERTY_NOTIFY_CLIENT,
566              Collections.<Object>singletonList(notifyClient));
567
568    props.putAll(super.getTaskPropertyValues());
569    return Collections.unmodifiableMap(props);
570  }
571}