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}