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