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