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 }