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.NotMutable; 036import com.unboundid.util.ThreadSafety; 037import com.unboundid.util.ThreadSafetyLevel; 038 039import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 040import static com.unboundid.util.Debug.*; 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 Alcatel-Lucent 8661 052 * server products. These classes provide support for proprietary 053 * functionality or for external specifications that are not considered stable 054 * or mature enough to be guaranteed to work in an interoperable way with 055 * 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 /** 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 super(taskID, DISCONNECT_CLIENT_TASK_CLASS, scheduledStartTime, 256 dependencyIDs, failedDependencyAction, notifyOnCompletion, 257 notifyOnError); 258 259 this.connectionID = connectionID; 260 this.disconnectMessage = disconnectMessage; 261 this.notifyClient = notifyClient; 262 } 263 264 265 266 /** 267 * Creates a new disconnect client task from the provided entry. 268 * 269 * @param entry The entry to use to create this disconnect client task. 270 * 271 * @throws TaskException If the provided entry cannot be parsed as a 272 * disconnect client task entry. 273 */ 274 public DisconnectClientTask(final Entry entry) 275 throws TaskException 276 { 277 super(entry); 278 279 280 // Get the connection ID. It must be present. 281 final String idStr = entry.getAttributeValue(ATTR_CONNECTION_ID); 282 if (idStr == null) 283 { 284 throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get( 285 getTaskEntryDN())); 286 } 287 else 288 { 289 try 290 { 291 connectionID = Long.parseLong(idStr); 292 } 293 catch (final Exception e) 294 { 295 debugException(e); 296 throw new TaskException(ERR_DISCONNECT_TASK_CONN_ID_NOT_LONG.get( 297 getTaskEntryDN(), idStr), 298 e); 299 } 300 } 301 302 303 // Get the disconnect message. It may be absent. 304 disconnectMessage = entry.getAttributeValue(ATTR_DISCONNECT_MESSAGE); 305 306 307 // Determine whether to notify the client. It may be absent. 308 notifyClient = parseBooleanValue(entry, ATTR_NOTIFY_CLIENT, false); 309 } 310 311 312 313 /** 314 * Creates a new disconnect client task from the provided set of task 315 * properties. 316 * 317 * @param properties The set of task properties and their corresponding 318 * values to use for the task. It must not be 319 * {@code null}. 320 * 321 * @throws TaskException If the provided set of properties cannot be used to 322 * create a valid disconnect client task. 323 */ 324 public DisconnectClientTask(final Map<TaskProperty,List<Object>> properties) 325 throws TaskException 326 { 327 super(DISCONNECT_CLIENT_TASK_CLASS, properties); 328 329 boolean notify = false; 330 Long connID = null; 331 String msg = null; 332 333 334 for (final Map.Entry<TaskProperty,List<Object>> entry : 335 properties.entrySet()) 336 { 337 final TaskProperty p = entry.getKey(); 338 final String attrName = p.getAttributeName(); 339 final List<Object> values = entry.getValue(); 340 341 if (attrName.equalsIgnoreCase(ATTR_CONNECTION_ID)) 342 { 343 connID = parseLong(p, values, connID); 344 } 345 else if (attrName.equalsIgnoreCase(ATTR_DISCONNECT_MESSAGE)) 346 { 347 msg = parseString(p, values, msg); 348 } 349 else if (attrName.equalsIgnoreCase(ATTR_NOTIFY_CLIENT)) 350 { 351 notify = parseBoolean(p, values, notify); 352 } 353 } 354 355 if (connID == null) 356 { 357 throw new TaskException(ERR_DISCONNECT_TASK_NO_CONN_ID.get( 358 getTaskEntryDN())); 359 } 360 361 connectionID = connID; 362 disconnectMessage = msg; 363 notifyClient = notify; 364 } 365 366 367 368 /** 369 * {@inheritDoc} 370 */ 371 @Override() 372 public String getTaskName() 373 { 374 return INFO_TASK_NAME_DISCONNECT_CLIENT.get(); 375 } 376 377 378 379 /** 380 * {@inheritDoc} 381 */ 382 @Override() 383 public String getTaskDescription() 384 { 385 return INFO_TASK_DESCRIPTION_DISCONNECT_CLIENT.get(); 386 } 387 388 389 390 /** 391 * Retrieves the connection ID of the client connection to disconnect. 392 * 393 * @return The connection ID of the client connection to disconnect. 394 */ 395 public long getConnectionID() 396 { 397 return connectionID; 398 } 399 400 401 402 /** 403 * Retrieves the disconnect message to provide to the server, and potentially 404 * to the client. 405 * 406 * @return The disconnect message, or {@code null} if no message is to be 407 * provided. 408 */ 409 public String getDisconnectMessage() 410 { 411 return disconnectMessage; 412 } 413 414 415 416 /** 417 * Indicates whether to send a notice of disconnection message to the client 418 * before terminating the connection. 419 * 420 * @return {@code true} if the server should send a notice of disconnection 421 * to the client, or {@code false} if it should terminate the 422 * connection without warning. 423 */ 424 public boolean notifyClient() 425 { 426 return notifyClient; 427 } 428 429 430 431 /** 432 * {@inheritDoc} 433 */ 434 @Override() 435 protected List<String> getAdditionalObjectClasses() 436 { 437 return Arrays.asList(OC_DISCONNECT_CLIENT_TASK); 438 } 439 440 441 442 /** 443 * {@inheritDoc} 444 */ 445 @Override() 446 protected List<Attribute> getAdditionalAttributes() 447 { 448 final ArrayList<Attribute> attrs = new ArrayList<Attribute>(3); 449 450 attrs.add(new Attribute(ATTR_CONNECTION_ID, String.valueOf(connectionID))); 451 attrs.add(new Attribute(ATTR_NOTIFY_CLIENT, String.valueOf(notifyClient))); 452 453 if (disconnectMessage != null) 454 { 455 attrs.add(new Attribute(ATTR_DISCONNECT_MESSAGE, disconnectMessage)); 456 } 457 458 return attrs; 459 } 460 461 462 463 /** 464 * {@inheritDoc} 465 */ 466 @Override() 467 public List<TaskProperty> getTaskSpecificProperties() 468 { 469 final List<TaskProperty> propList = Arrays.asList( 470 PROPERTY_CONNECTION_ID, 471 PROPERTY_DISCONNECT_MESSAGE, 472 PROPERTY_NOTIFY_CLIENT); 473 474 return Collections.unmodifiableList(propList); 475 } 476 477 478 479 /** 480 * {@inheritDoc} 481 */ 482 @Override() 483 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 484 { 485 final LinkedHashMap<TaskProperty,List<Object>> props = 486 new LinkedHashMap<TaskProperty,List<Object>>(); 487 488 props.put(PROPERTY_CONNECTION_ID, 489 Collections.<Object>unmodifiableList(Arrays.asList( 490 connectionID))); 491 492 if (disconnectMessage == null) 493 { 494 props.put(PROPERTY_DISCONNECT_MESSAGE, Collections.emptyList()); 495 } 496 else 497 { 498 props.put(PROPERTY_DISCONNECT_MESSAGE, 499 Collections.<Object>unmodifiableList(Arrays.asList( 500 disconnectMessage))); 501 } 502 503 props.put(PROPERTY_NOTIFY_CLIENT, 504 Collections.<Object>unmodifiableList(Arrays.asList( 505 notifyClient))); 506 507 props.putAll(super.getTaskPropertyValues()); 508 return Collections.unmodifiableMap(props); 509 } 510}