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