001/* 002 * Copyright 2018-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2018-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) 2018-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.Collection; 043import java.util.Collections; 044import java.util.Date; 045import java.util.LinkedHashMap; 046import java.util.LinkedList; 047import java.util.List; 048import java.util.Map; 049import java.util.concurrent.TimeUnit; 050 051import com.unboundid.ldap.sdk.Attribute; 052import com.unboundid.ldap.sdk.Entry; 053import com.unboundid.ldap.sdk.LDAPException; 054import com.unboundid.ldap.sdk.LDAPURL; 055import com.unboundid.util.Debug; 056import com.unboundid.util.NotMutable; 057import com.unboundid.util.StaticUtils; 058import com.unboundid.util.ThreadSafety; 059import com.unboundid.util.ThreadSafetyLevel; 060import com.unboundid.util.args.ArgumentException; 061import com.unboundid.util.args.DurationArgument; 062 063import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 064 065 066 067/** 068 * This class defines a Directory Server task that simply sleeps for a specified 069 * length of time or until a given condition occurs. It is primarily intended 070 * to act as a separator between other tasks in a dependency chain. 071 * <BR> 072 * <BLOCKQUOTE> 073 * <B>NOTE:</B> This class, and other classes within the 074 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 075 * supported for use against Ping Identity, UnboundID, and 076 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 077 * for proprietary functionality or for external specifications that are not 078 * considered stable or mature enough to be guaranteed to work in an 079 * interoperable way with other types of LDAP servers. 080 * </BLOCKQUOTE> 081 */ 082@NotMutable() 083@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 084public final class DelayTask 085 extends Task 086{ 087 /** 088 * The fully-qualified name of the Java class that is used for the delay task. 089 */ 090 static final String DELAY_TASK_CLASS = 091 "com.unboundid.directory.server.tasks.DelayTask"; 092 093 094 095 /** 096 * The name of the attribute used to specify the length of time that the 097 * task should sleep. 098 */ 099 private static final String ATTR_SLEEP_DURATION = 100 "ds-task-delay-sleep-duration"; 101 102 103 104 /** 105 * The name of the task attribute that indicates whether to wait for the work 106 * queue to become idle. 107 */ 108 private static final String ATTR_WAIT_FOR_WORK_QUEUE_IDLE = 109 "ds-task-delay-duration-to-wait-for-work-queue-idle"; 110 111 112 113 /** 114 * The name of the task attribute that provides a set of LDAP URLs to use to 115 * issue searches that are expected to eventually return entries. 116 */ 117 private static final String ATTR_SEARCH_URL = 118 "ds-task-delay-ldap-url-for-search-expected-to-return-entries"; 119 120 121 122 /** 123 * The name of the task attribute that specifies the length of time between 124 * searches. 125 */ 126 private static final String ATTR_SEARCH_INTERVAL = 127 "ds-task-delay-search-interval"; 128 129 130 131 /** 132 * The name of the task attribute that specifies the time limit for each 133 * search. 134 */ 135 private static final String ATTR_SEARCH_TIME_LIMIT = 136 "ds-task-delay-search-time-limit"; 137 138 139 140 /** 141 * The name of the task attribute that specifies the total length of time to 142 * wait for each search to return one or more entries. 143 */ 144 private static final String ATTR_SEARCH_DURATION = 145 "ds-task-delay-duration-to-wait-for-search-to-return-entries"; 146 147 148 149 /** 150 * The name of the task attribute that specifies the task return state to use 151 * if a timeout is encountered during processing. 152 */ 153 private static final String ATTR_TIMEOUT_RETURN_STATE = 154 "ds-task-delay-task-return-state-if-timeout-is-encountered"; 155 156 157 158 /** 159 * The name of the object class used in delay task entries. 160 */ 161 private static final String OC_DELAY_TASK = "ds-task-delay"; 162 163 164 165 /** 166 * The task property that will be used for the sleep duration. 167 */ 168 private static final TaskProperty PROPERTY_SLEEP_DURATION_MILLIS = 169 new TaskProperty(ATTR_SLEEP_DURATION, 170 INFO_DELAY_DISPLAY_NAME_SLEEP_DURATION.get(), 171 INFO_DELAY_DESCRIPTION_SLEEP_DURATION.get(), Long.class, false, 172 false, false); 173 174 175 176 /** 177 * The task property that will be used for the length of time to wait for the 178 * work queue to report that the server is idle. 179 */ 180 private static final TaskProperty PROPERTY_WAIT_FOR_WORK_QUEUE_IDLE_MILLIS = 181 new TaskProperty(ATTR_WAIT_FOR_WORK_QUEUE_IDLE, 182 INFO_DELAY_DISPLAY_NAME_WAIT_FOR_WORK_QUEUE_IDLE.get(), 183 INFO_DELAY_DESCRIPTION_WAIT_FOR_WORK_QUEUE_IDLE.get(), Long.class, 184 false, false, false); 185 186 187 188 /** 189 * The task property that will be used to provide LDAP URLs for searches that 190 * are expected to eventually return entries. 191 */ 192 private static final TaskProperty PROPERTY_SEARCH_URL = 193 new TaskProperty(ATTR_SEARCH_URL, 194 INFO_DELAY_DISPLAY_NAME_SEARCH_URL.get(), 195 INFO_DELAY_DESCRIPTION_SEARCH_URL.get(), String.class, false, true, 196 false); 197 198 199 200 /** 201 * The task property that will be used to specify the length of time between 202 * searches. 203 */ 204 private static final TaskProperty PROPERTY_SEARCH_INTERVAL_MILLIS = 205 new TaskProperty(ATTR_SEARCH_INTERVAL, 206 INFO_DELAY_DISPLAY_NAME_SEARCH_INTERVAL.get(), 207 INFO_DELAY_DESCRIPTION_SEARCH_INTERVAL.get(), Long.class, false, 208 false, false); 209 210 211 212 /** 213 * The task property that will be used to specify the time limit for each 214 * search. 215 */ 216 private static final TaskProperty PROPERTY_SEARCH_TIME_LIMIT_MILLIS = 217 new TaskProperty(ATTR_SEARCH_TIME_LIMIT, 218 INFO_DELAY_DISPLAY_NAME_SEARCH_TIME_LIMIT.get(), 219 INFO_DELAY_DESCRIPTION_SEARCH_TIME_LIMIT.get(), Long.class, false, 220 false, false); 221 222 223 224 /** 225 * The task property that will be used to specify the total length of time 226 * allowed for a search to return entries. 227 */ 228 private static final TaskProperty PROPERTY_SEARCH_DURATION_MILLIS = 229 new TaskProperty(ATTR_SEARCH_DURATION, 230 INFO_DELAY_DISPLAY_NAME_SEARCH_DURATION.get(), 231 INFO_DELAY_DESCRIPTION_SEARCH_DURATION.get(), Long.class, false, 232 false, false); 233 234 235 236 /** 237 * The task property that will be used for the task return state if a timeout 238 * is encountered. 239 */ 240 private static final TaskProperty PROPERTY_TIMEOUT_RETURN_STATE = 241 new TaskProperty(ATTR_TIMEOUT_RETURN_STATE, 242 INFO_DELAY_DISPLAY_NAME_TIMEOUT_RETURN_STATE.get(), 243 INFO_DELAY_DESCRIPTION_TIMEOUT_RETURN_STATE.get(), 244 String.class, false, false, false, 245 new String[] 246 { 247 "STOPPED_BY_ERROR", 248 "STOPPED-BY-ERROR", 249 "COMPLETED_WITH_ERRORS", 250 "COMPLETED-WITH-ERRORS", 251 "COMPLETED_SUCCESSFULLY", 252 "COMPLETED-SUCCESSFULLY" 253 }); 254 255 256 257 /** 258 * The serial version UID for this serializable class. 259 */ 260 private static final long serialVersionUID = -639870096358259180L; 261 262 263 264 // A list of LDAP URLs that define searches that are expected to return 265 // entries. 266 private final List<LDAPURL> ldapURLsForSearchesExpectedToReturnEntries; 267 268 // The length of time, in milliseconds, between each search. 269 private final Long millisBetweenSearches; 270 271 // The maximum length of time, in milliseconds, that the task should wait for 272 // the work queue to report that the server is idle. 273 private final Long millisToWaitForWorkQueueToBecomeIdle; 274 275 // The maximum length of time, in milliseconds, to wait for a response to 276 // each search. 277 private final Long searchTimeLimitMillis; 278 279 // The length of time, in milliseconds, that the task should sleep. 280 private final Long sleepDurationMillis; 281 282 // The maximum length of time, in milliseconds, to wait for each search to 283 // return at least one entry. 284 private final Long totalDurationMillisForEachLDAPURL; 285 286 // The task state that should be returned if a timeout is encountered during 287 // task processing. 288 private final String taskStateIfTimeoutIsEncountered; 289 290 291 292 /** 293 * Creates a new, uninitialized delay task instance that should only be used 294 * for obtaining general information about this task, including the task name, 295 * description, and supported properties. Attempts to use a task created with 296 * this constructor for any other reason will likely fail. 297 */ 298 public DelayTask() 299 { 300 ldapURLsForSearchesExpectedToReturnEntries = null; 301 millisBetweenSearches = null; 302 millisToWaitForWorkQueueToBecomeIdle = null; 303 searchTimeLimitMillis = null; 304 sleepDurationMillis = null; 305 totalDurationMillisForEachLDAPURL = null; 306 taskStateIfTimeoutIsEncountered = null; 307 } 308 309 310 311 /** 312 * Creates a new delay task with the provided information. 313 * 314 * @param sleepDurationMillis 315 * The length of time, in milliseconds, that the task should 316 * sleep. This may be {@code null} if the task is intended to 317 * wait for the work queue to become idle or searches to return 318 * entries and no additional sleep is required. If it is not 319 * {@code null}, then it must be greater than zero. If a sleep 320 * duration is provided and the task should also wait for the work 321 * queue to become idle or wait for search results, then the sleep 322 * for this duration will occur after waiting for those other 323 * conditions to be satisfied (or for a timeout to occur). 324 * @param millisToWaitForWorkQueueToBecomeIdle 325 * The length of time, in milliseconds, that the task should wait 326 * for the server work queue to report that there are no pending 327 * requests and all worker threads are idle. This may be 328 * {@code null} if the task should not wait for the work queue to 329 * become idle. If it is not {@code null}, then it must be 330 * greater than zero. 331 * @param ldapURLsForSearchesExpectedToReturnEntries 332 * A list of LDAP URLs that provide criteria for search requests 333 * that are eventually expected to return one or more entries. 334 * This may be {@code null} or empty if the task should not 335 * perform any such searches. If this is non-empty, then the 336 * {@code millisBetweenSearches}, 337 * {@code searchTimeLimitMillis}, and 338 * {@code totalDurationMillisForEachLDAPURL} arguments must be 339 * non-{@code null}. 340 * @param millisBetweenSearches 341 * The length of time, in milliseconds, between the individual 342 * searches created from each of the provided LDAP URLs. Each 343 * search created from an LDAP URL will be repeated until it 344 * returns at least one entry, or until the total length of time 345 * processing that search meets or exceeds the value of the 346 * {@code totalDurationMillisForEachSearch} argument. If the 347 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is not 348 * empty, then this must not be {@code null}. If it is not 349 * {@code null}, then it must be greater than zero. 350 * @param searchTimeLimitMillis 351 * The maximum length of time, in milliseconds, to wait for a 352 * response to each individual search created from one of the 353 * provided LDAP URLs. If the 354 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is 355 * not empty, then this must not be {@code null}. If it is not 356 * {@code null}, then it must be greater than zero. 357 * @param totalDurationMillisForEachLDAPURL 358 * The maximum length of time, in milliseconds, to wait for the 359 * search criteria created from each of the provided LDAP URLs 360 * to match at least one entry. If the 361 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is 362 * not empty, then this must not be {@code null}. If it is not 363 * {@code null}, then it must be greater than zero. 364 * @param taskStateIfTimeoutIsEncountered 365 * The task state that should be used if a timeout is encountered 366 * while waiting for the work queue to become idle or while 367 * waiting for search criteria created from an LDAP URL to match 368 * at least one entry. This may be {@code null} to indicate that 369 * the server should determine the appropriate task state. If it 370 * is non-{@code null}, then the value must be one of 371 * {@link TaskState#STOPPED_BY_ERROR}, 372 * {@link TaskState#COMPLETED_WITH_ERRORS}, or 373 * {@link TaskState#COMPLETED_SUCCESSFULLY}. 374 * 375 * @throws TaskException If there is a problem with any of the provided 376 * arguments. 377 */ 378 public DelayTask(final Long sleepDurationMillis, 379 final Long millisToWaitForWorkQueueToBecomeIdle, 380 final Collection<LDAPURL> ldapURLsForSearchesExpectedToReturnEntries, 381 final Long millisBetweenSearches, final Long searchTimeLimitMillis, 382 final Long totalDurationMillisForEachLDAPURL, 383 final TaskState taskStateIfTimeoutIsEncountered) 384 throws TaskException 385 { 386 this(null, sleepDurationMillis, millisToWaitForWorkQueueToBecomeIdle, 387 ldapURLsForSearchesExpectedToReturnEntries, millisBetweenSearches, 388 searchTimeLimitMillis, totalDurationMillisForEachLDAPURL, 389 taskStateIfTimeoutIsEncountered, null, null, null, null, null, null, 390 null, null, null, null); 391 } 392 393 394 395 /** 396 * Creates a new delay task with the provided information. 397 * 398 * @param taskID 399 * The task ID to use for this task. If it is {@code null} then 400 * a UUID will be generated for use as the task ID. 401 * @param sleepDurationMillis 402 * The length of time, in milliseconds, that the task should 403 * sleep. This may be {@code null} if the task is intended to 404 * wait for the work queue to become idle or searches to return 405 * entries and no additional sleep is required. If it is not 406 * {@code null}, then it must be greater than zero. If a sleep 407 * duration is provided and the task should also wait for the work 408 * queue to become idle or wait for search results, then the sleep 409 * for this duration will occur after waiting for those other 410 * conditions to be satisfied (or for a timeout to occur). 411 * @param millisToWaitForWorkQueueToBecomeIdle 412 * The length of time, in milliseconds, that the task should wait 413 * for the server work queue to report that there are no pending 414 * requests and all worker threads are idle. This may be 415 * {@code null} if the task should not wait for the work queue to 416 * become idle. If it is not {@code null}, then it must be 417 * greater than zero. 418 * @param ldapURLsForSearchesExpectedToReturnEntries 419 * A list of LDAP URLs that provide criteria for search requests 420 * that are eventually expected to return one or more entries. 421 * This may be {@code null} or empty if the task should not 422 * perform any such searches. If this is non-empty, then the 423 * {@code millisBetweenSearches}, 424 * {@code searchTimeLimitMillis}, and 425 * {@code totalDurationMillisForEachLDAPURL} arguments must be 426 * non-{@code null}. 427 * @param millisBetweenSearches 428 * The length of time, in milliseconds, between the individual 429 * searches created from each of the provided LDAP URLs. Each 430 * search created from an LDAP URL will be repeated until it 431 * returns at least one entry, or until the total length of time 432 * processing that search meets or exceeds the value of the 433 * {@code totalDurationMillisForEachSearch} argument. If the 434 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is not 435 * empty, then this must not be {@code null}. If it is not 436 * {@code null}, then it must be greater than zero. 437 * @param searchTimeLimitMillis 438 * The maximum length of time, in milliseconds, to wait for a 439 * response to each individual search created from one of the 440 * provided LDAP URLs. If the 441 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is 442 * not empty, then this must not be {@code null}. If it is not 443 * {@code null}, then it must be greater than zero. 444 * @param totalDurationMillisForEachLDAPURL 445 * The maximum length of time, in milliseconds, to wait for the 446 * search criteria created from each of the provided LDAP URLs 447 * to match at least one entry. If the 448 * {@code ldapURLsForSearchesExpectedToReturnEntries} list is 449 * not empty, then this must not be {@code null}. If it is not 450 * {@code null}, then it must be greater than zero. 451 * @param taskStateIfTimeoutIsEncountered 452 * The task state that should be used if a timeout is encountered 453 * while waiting for the work queue to become idle or while 454 * waiting for search criteria created from an LDAP URL to match 455 * at least one entry. This may be {@code null} to indicate that 456 * the server should determine the appropriate task state. If it 457 * is non-{@code null}, then the value must be one of 458 * {@link TaskState#STOPPED_BY_ERROR}, 459 * {@link TaskState#COMPLETED_WITH_ERRORS}, or 460 * {@link TaskState#COMPLETED_SUCCESSFULLY}. 461 * @param scheduledStartTime 462 * The time that this task should start running. 463 * @param dependencyIDs 464 * The list of task IDs that will be required to complete before 465 * this task will be eligible to start. 466 * @param failedDependencyAction 467 * Indicates what action should be taken if any of the 468 * dependencies for this task do not complete successfully. 469 * @param notifyOnStart 470 * The list of e-mail addresses of individuals that should be 471 * notified when this task starts. 472 * @param notifyOnCompletion 473 * The list of e-mail addresses of individuals that should be 474 * notified when this task completes. 475 * @param notifyOnSuccess 476 * The list of e-mail addresses of individuals that should be 477 * notified if this task completes successfully. 478 * @param notifyOnError 479 * The list of e-mail addresses of individuals that should be 480 * notified if this task does not complete successfully. 481 * @param alertOnStart 482 * Indicates whether the server should send an alert notification 483 * when this task starts. 484 * @param alertOnSuccess 485 * Indicates whether the server should send an alert notification 486 * if this task completes successfully. 487 * @param alertOnError 488 * Indicates whether the server should send an alert notification 489 * if this task fails to complete successfully. 490 * 491 * @throws TaskException If there is a problem with any of the provided 492 * arguments. 493 */ 494 public DelayTask(final String taskID, final Long sleepDurationMillis, 495 final Long millisToWaitForWorkQueueToBecomeIdle, 496 final Collection<LDAPURL> ldapURLsForSearchesExpectedToReturnEntries, 497 final Long millisBetweenSearches, final Long searchTimeLimitMillis, 498 final Long totalDurationMillisForEachLDAPURL, 499 final TaskState taskStateIfTimeoutIsEncountered, 500 final Date scheduledStartTime, final List<String> dependencyIDs, 501 final FailedDependencyAction failedDependencyAction, 502 final List<String> notifyOnStart, final List<String> notifyOnCompletion, 503 final List<String> notifyOnSuccess, final List<String> notifyOnError, 504 final Boolean alertOnStart, final Boolean alertOnSuccess, 505 final Boolean alertOnError) 506 throws TaskException 507 { 508 super(taskID, DELAY_TASK_CLASS, scheduledStartTime, dependencyIDs, 509 failedDependencyAction, notifyOnStart, notifyOnCompletion, 510 notifyOnSuccess, notifyOnError, alertOnStart, alertOnSuccess, 511 alertOnError); 512 513 this.sleepDurationMillis = sleepDurationMillis; 514 this.millisToWaitForWorkQueueToBecomeIdle = 515 millisToWaitForWorkQueueToBecomeIdle; 516 this.millisBetweenSearches = millisBetweenSearches; 517 this.searchTimeLimitMillis = searchTimeLimitMillis; 518 this.totalDurationMillisForEachLDAPURL = totalDurationMillisForEachLDAPURL; 519 520 if (ldapURLsForSearchesExpectedToReturnEntries == null) 521 { 522 this.ldapURLsForSearchesExpectedToReturnEntries = Collections.emptyList(); 523 } 524 else 525 { 526 this.ldapURLsForSearchesExpectedToReturnEntries = 527 Collections.unmodifiableList( 528 new ArrayList<>(ldapURLsForSearchesExpectedToReturnEntries)); 529 } 530 531 if (taskStateIfTimeoutIsEncountered == null) 532 { 533 this.taskStateIfTimeoutIsEncountered = null; 534 } 535 else 536 { 537 switch (taskStateIfTimeoutIsEncountered) 538 { 539 case STOPPED_BY_ERROR: 540 case COMPLETED_WITH_ERRORS: 541 case COMPLETED_SUCCESSFULLY: 542 this.taskStateIfTimeoutIsEncountered = 543 taskStateIfTimeoutIsEncountered.name(); 544 break; 545 default: 546 throw new TaskException( 547 ERR_DELAY_INVALID_TIMEOUT_STATE.get( 548 TaskState.STOPPED_BY_ERROR.name(), 549 TaskState.COMPLETED_WITH_ERRORS.name(), 550 TaskState.COMPLETED_SUCCESSFULLY.name())); 551 } 552 } 553 554 if ((sleepDurationMillis != null) && (sleepDurationMillis <= 0L)) 555 { 556 throw new TaskException(ERR_DELAY_INVALID_SLEEP_DURATION.get()); 557 } 558 559 if ((millisToWaitForWorkQueueToBecomeIdle != null) && 560 (millisToWaitForWorkQueueToBecomeIdle <= 0L)) 561 { 562 throw new TaskException(ERR_DELAY_INVALID_WAIT_FOR_QUEUE_IDLE.get()); 563 } 564 565 if ((millisBetweenSearches != null) && (millisBetweenSearches <= 0L)) 566 { 567 throw new TaskException(ERR_DELAY_INVALID_SEARCH_INTERVAL.get()); 568 } 569 570 if ((searchTimeLimitMillis != null) && (searchTimeLimitMillis <= 0L)) 571 { 572 throw new TaskException(ERR_DELAY_INVALID_SEARCH_TIME_LIMIT.get()); 573 } 574 575 if ((totalDurationMillisForEachLDAPURL != null) && 576 (totalDurationMillisForEachLDAPURL <= 0L)) 577 { 578 throw new TaskException(ERR_DELAY_INVALID_SEARCH_DURATION.get()); 579 } 580 581 if (! this.ldapURLsForSearchesExpectedToReturnEntries.isEmpty()) 582 { 583 if ((millisBetweenSearches == null) || 584 (searchTimeLimitMillis == null) || 585 (totalDurationMillisForEachLDAPURL == null)) 586 { 587 throw new TaskException(ERR_DELAY_URL_WITHOUT_REQUIRED_PARAM.get()); 588 } 589 590 if (millisBetweenSearches >= totalDurationMillisForEachLDAPURL) 591 { 592 throw new TaskException(ERR_DELAY_INVALID_SEARCH_INTERVAL.get()); 593 } 594 595 if (searchTimeLimitMillis >= totalDurationMillisForEachLDAPURL) 596 { 597 throw new TaskException(ERR_DELAY_INVALID_SEARCH_TIME_LIMIT.get()); 598 } 599 } 600 } 601 602 603 604 /** 605 * Creates a new delay task from the provided entry. 606 * 607 * @param entry The entry to use to create this delay task. 608 * 609 * @throws TaskException If the provided entry cannot be parsed as an delay 610 * task entry. 611 */ 612 public DelayTask(final Entry entry) 613 throws TaskException 614 { 615 super(entry); 616 617 618 // Get the name of the task state to use if a timeout occurs during task 619 // processing. 620 taskStateIfTimeoutIsEncountered = 621 entry.getAttributeValue(ATTR_TIMEOUT_RETURN_STATE); 622 623 624 // Parse the duration attributes. 625 sleepDurationMillis = parseDuration(entry, ATTR_SLEEP_DURATION); 626 millisToWaitForWorkQueueToBecomeIdle = 627 parseDuration(entry,ATTR_WAIT_FOR_WORK_QUEUE_IDLE); 628 millisBetweenSearches = parseDuration(entry, ATTR_SEARCH_INTERVAL); 629 searchTimeLimitMillis = parseDuration(entry, ATTR_SEARCH_TIME_LIMIT); 630 totalDurationMillisForEachLDAPURL = 631 parseDuration(entry, ATTR_SEARCH_DURATION); 632 633 634 // Parse the set of LDAP URLs. 635 final String[] urlStrings = entry.getAttributeValues(ATTR_SEARCH_URL); 636 if (urlStrings == null) 637 { 638 ldapURLsForSearchesExpectedToReturnEntries = Collections.emptyList(); 639 } 640 else 641 { 642 final ArrayList<LDAPURL> urls = new ArrayList<>(urlStrings.length); 643 for (final String s : urlStrings) 644 { 645 try 646 { 647 urls.add(new LDAPURL(s)); 648 } 649 catch (final LDAPException e) 650 { 651 Debug.debugException(e); 652 throw new TaskException( 653 ERR_DELAY_ENTRY_MALFORMED_URL.get(ATTR_SEARCH_URL, s, 654 e.getMessage()), 655 e); 656 } 657 } 658 659 ldapURLsForSearchesExpectedToReturnEntries = 660 Collections.unmodifiableList(urls); 661 } 662 } 663 664 665 666 /** 667 * Retrieves the value of the specified attribute from the given entry and 668 * parses its value as a duration. 669 * 670 * @param entry The entry from which to retrieve the attribute. 671 * @param attributeName The name of the attribute containing the value to 672 * parse. It must not be {@code null}. 673 * 674 * @return The number of milliseconds in the duration represented by the 675 * value of the specified attribute, or {@code null} if the attribute 676 * was not present in the entry. 677 * 678 * @throws TaskException If the attribute value cannot be parsed as a 679 * duration. 680 */ 681 private static Long parseDuration(final Entry entry, 682 final String attributeName) 683 throws TaskException 684 { 685 final String value = entry.getAttributeValue(attributeName); 686 if (value == null) 687 { 688 return null; 689 } 690 691 try 692 { 693 return DurationArgument.parseDuration(value, TimeUnit.MILLISECONDS); 694 } 695 catch (final ArgumentException e) 696 { 697 throw new TaskException( 698 ERR_DELAY_CANNOT_PARSE_ATTR_VALUE_AS_DURATION.get(attributeName, 699 e.getMessage()), 700 e); 701 } 702 } 703 704 705 706 /** 707 * Creates a new delay task from the provided set of task properties. 708 * 709 * @param properties The set of task properties and their corresponding 710 * values to use for the task. It must not be 711 * {@code null}. 712 * 713 * @throws TaskException If the provided set of properties cannot be used to 714 * create a valid delay task. 715 */ 716 public DelayTask(final Map<TaskProperty,List<Object>> properties) 717 throws TaskException 718 { 719 super(DELAY_TASK_CLASS, properties); 720 721 Long searchDuration = null; 722 Long searchInterval = null; 723 Long searchTimeLimit = null; 724 Long sleepDuration = null; 725 Long workQueueWaitTime = null; 726 String timeoutReturnState = null; 727 final List<LDAPURL> urls = new ArrayList<>(10); 728 for (final Map.Entry<TaskProperty,List<Object>> entry : 729 properties.entrySet()) 730 { 731 final TaskProperty p = entry.getKey(); 732 final String attrName = StaticUtils.toLowerCase(p.getAttributeName()); 733 final List<Object> values = entry.getValue(); 734 switch (attrName) 735 { 736 case ATTR_SLEEP_DURATION: 737 sleepDuration = parseLong(p, values, null); 738 break; 739 case ATTR_WAIT_FOR_WORK_QUEUE_IDLE: 740 workQueueWaitTime = parseLong(p, values, null); 741 break; 742 case ATTR_SEARCH_URL: 743 for (final String urlString : 744 parseStrings(p, values, StaticUtils.NO_STRINGS)) 745 { 746 try 747 { 748 urls.add(new LDAPURL(urlString)); 749 } 750 catch (final LDAPException e) 751 { 752 Debug.debugException(e); 753 throw new TaskException( 754 ERR_DELAY_ENTRY_MALFORMED_URL.get(ATTR_SEARCH_URL, urlString, 755 e.getMessage()), 756 e); 757 } 758 } 759 break; 760 case ATTR_SEARCH_INTERVAL: 761 searchInterval = parseLong(p, values, null); 762 break; 763 case ATTR_SEARCH_TIME_LIMIT: 764 searchTimeLimit = parseLong(p, values, null); 765 break; 766 case ATTR_SEARCH_DURATION: 767 searchDuration = parseLong(p, values, null); 768 break; 769 case ATTR_TIMEOUT_RETURN_STATE: 770 timeoutReturnState = parseString(p, values, null); 771 break; 772 } 773 } 774 775 sleepDurationMillis = sleepDuration; 776 millisToWaitForWorkQueueToBecomeIdle = workQueueWaitTime; 777 ldapURLsForSearchesExpectedToReturnEntries = 778 Collections.unmodifiableList(urls); 779 millisBetweenSearches = searchInterval; 780 searchTimeLimitMillis = searchTimeLimit; 781 totalDurationMillisForEachLDAPURL = searchDuration; 782 taskStateIfTimeoutIsEncountered = timeoutReturnState; 783 } 784 785 786 787 /** 788 * {@inheritDoc} 789 */ 790 @Override() 791 public String getTaskName() 792 { 793 return INFO_TASK_NAME_DELAY.get(); 794 } 795 796 797 798 /** 799 * {@inheritDoc} 800 */ 801 @Override() 802 public String getTaskDescription() 803 { 804 return INFO_TASK_DESCRIPTION_DELAY.get(); 805 } 806 807 808 809 /** 810 * Retrieves the length of time, in milliseconds, that the task should sleep. 811 * 812 * @return The length of time, in milliseconds, that the task should sleep, 813 * or {@code null} if the task should not sleep for a specified 814 * period of time. 815 */ 816 public Long getSleepDurationMillis() 817 { 818 return sleepDurationMillis; 819 } 820 821 822 823 /** 824 * Retrieves the length of time, in milliseconds, that the task should wait 825 * for the server work queue to report that there are no pending requests and 826 * all worker threads are idle. 827 * 828 * @return The length of time, in milliseconds, that the task should wait for 829 * the server work queue to report that it is idle, or {@code null} 830 * if the task should not wait for the work queue to be idle 831 */ 832 public Long getMillisToWaitForWorkQueueToBecomeIdle() 833 { 834 return millisToWaitForWorkQueueToBecomeIdle; 835 } 836 837 838 839 /** 840 * Retrieves a list of LDAP URLs that provide criteria for search requests 841 * that are eventually expected to return one or more entries. 842 * 843 * @return A list of LDAP URLs that provide criteria for search requests that 844 * are eventually expected to return one or more entries, or an empty 845 * list if no searches are to be performed. 846 */ 847 public List<LDAPURL> getLDAPURLsForSearchesExpectedToReturnEntries() 848 { 849 return ldapURLsForSearchesExpectedToReturnEntries; 850 } 851 852 853 854 /** 855 * Retrieves the length of time, in milliseconds, between the individual 856 * searches created from each of the provided LDAP URLs. Each search created 857 * from an LDAP URL will be repeated until it returns at least one entry, or 858 * until the total length of processing that search meets or exceeds the value 859 * returned by the {@link #getTotalDurationMillisForEachLDAPURL()} method. 860 * 861 * @return The length of time, in milliseconds, between the individual 862 * searches created from each of the provided LDAP URLs, or 863 * {@code null} if no searches are to be performed. 864 */ 865 public Long getMillisBetweenSearches() 866 { 867 return millisBetweenSearches; 868 } 869 870 871 872 /** 873 * Retrieves the maximum length of time, in milliseconds, to wait for a 874 * response to each individual search created from one of the provided LDAP 875 * URLs. 876 * 877 * @return The maximum length of time, in milliseconds, to wait for a 878 * response to each individual search created from one of the 879 * provided LDAP URLs, or {@code null} if no searches are to be 880 * performed. 881 */ 882 public Long getSearchTimeLimitMillis() 883 { 884 return searchTimeLimitMillis; 885 } 886 887 888 889 /** 890 * Retrieves the maximum length of time, in milliseconds, to wait for the 891 * search criteria created from each of the provided LDAP URLs to match at 892 * least one entry. 893 * 894 * @return The maximum length of time, in milliseconds, to wait for the 895 * search criteria created from each of the provided LDAP URLs to 896 * match at least one entry, or {@code null} if no searches are to be 897 * performed. 898 */ 899 public Long getTotalDurationMillisForEachLDAPURL() 900 { 901 return totalDurationMillisForEachLDAPURL; 902 } 903 904 905 906 /** 907 * Retrieves the name of the task state that should be used if a timeout is 908 * encountered while waiting for the work queue to become idle or while 909 * waiting for search criteria created from an LDAP URL to match at least one 910 * entry. 911 * 912 * @return The name of the task state that should be used if a timeout is 913 * encountered, or {@code null} if the server should determine the 914 * appropriate task state. 915 */ 916 public String getTaskStateIfTimeoutIsEncountered() 917 { 918 return taskStateIfTimeoutIsEncountered; 919 } 920 921 922 923 /** 924 * {@inheritDoc} 925 */ 926 @Override() 927 protected List<String> getAdditionalObjectClasses() 928 { 929 return Collections.singletonList(OC_DELAY_TASK); 930 } 931 932 933 934 /** 935 * {@inheritDoc} 936 */ 937 @Override() 938 protected List<Attribute> getAdditionalAttributes() 939 { 940 final LinkedList<Attribute> attrList = new LinkedList<>(); 941 942 if (sleepDurationMillis != null) 943 { 944 final long sleepDurationNanos = sleepDurationMillis * 1_000_000L; 945 attrList.add(new Attribute(ATTR_SLEEP_DURATION, 946 DurationArgument.nanosToDuration(sleepDurationNanos))); 947 } 948 949 if (millisToWaitForWorkQueueToBecomeIdle != null) 950 { 951 final long waitTimeNanos = 952 millisToWaitForWorkQueueToBecomeIdle * 1_000_000L; 953 attrList.add(new Attribute(ATTR_WAIT_FOR_WORK_QUEUE_IDLE, 954 DurationArgument.nanosToDuration(waitTimeNanos))); 955 } 956 957 if (! ldapURLsForSearchesExpectedToReturnEntries.isEmpty()) 958 { 959 final ArrayList<String> urlStrings = 960 new ArrayList<>(ldapURLsForSearchesExpectedToReturnEntries.size()); 961 for (final LDAPURL url : ldapURLsForSearchesExpectedToReturnEntries) 962 { 963 urlStrings.add(url.toString()); 964 } 965 966 attrList.add(new Attribute(ATTR_SEARCH_URL, urlStrings)); 967 } 968 969 if (millisBetweenSearches != null) 970 { 971 final long intervalNanos = millisBetweenSearches * 1_000_000L; 972 attrList.add(new Attribute(ATTR_SEARCH_INTERVAL, 973 DurationArgument.nanosToDuration(intervalNanos))); 974 } 975 976 if (searchTimeLimitMillis != null) 977 { 978 final long timeLimitNanos = searchTimeLimitMillis * 1_000_000L; 979 attrList.add(new Attribute(ATTR_SEARCH_TIME_LIMIT, 980 DurationArgument.nanosToDuration(timeLimitNanos))); 981 } 982 983 if (totalDurationMillisForEachLDAPURL != null) 984 { 985 final long durationNanos = totalDurationMillisForEachLDAPURL * 1_000_000L; 986 attrList.add(new Attribute(ATTR_SEARCH_DURATION, 987 DurationArgument.nanosToDuration(durationNanos))); 988 } 989 990 if (taskStateIfTimeoutIsEncountered != null) 991 { 992 attrList.add(new Attribute(ATTR_TIMEOUT_RETURN_STATE, 993 taskStateIfTimeoutIsEncountered)); 994 } 995 996 return attrList; 997 } 998 999 1000 1001 /** 1002 * {@inheritDoc} 1003 */ 1004 @Override() 1005 public List<TaskProperty> getTaskSpecificProperties() 1006 { 1007 return Collections.unmodifiableList(Arrays.asList( 1008 PROPERTY_SLEEP_DURATION_MILLIS, 1009 PROPERTY_WAIT_FOR_WORK_QUEUE_IDLE_MILLIS, 1010 PROPERTY_SEARCH_URL, 1011 PROPERTY_SEARCH_INTERVAL_MILLIS, 1012 PROPERTY_SEARCH_TIME_LIMIT_MILLIS, 1013 PROPERTY_SEARCH_DURATION_MILLIS, 1014 PROPERTY_TIMEOUT_RETURN_STATE)); 1015 } 1016 1017 1018 1019 /** 1020 * {@inheritDoc} 1021 */ 1022 @Override() 1023 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 1024 { 1025 final LinkedHashMap<TaskProperty, List<Object>> props = 1026 new LinkedHashMap<>(StaticUtils.computeMapCapacity(7)); 1027 1028 if (sleepDurationMillis != null) 1029 { 1030 props.put(PROPERTY_SLEEP_DURATION_MILLIS, 1031 Collections.<Object>singletonList(sleepDurationMillis)); 1032 } 1033 1034 if (millisToWaitForWorkQueueToBecomeIdle != null) 1035 { 1036 props.put(PROPERTY_WAIT_FOR_WORK_QUEUE_IDLE_MILLIS, 1037 Collections.<Object>singletonList( 1038 millisToWaitForWorkQueueToBecomeIdle)); 1039 } 1040 1041 if (! ldapURLsForSearchesExpectedToReturnEntries.isEmpty()) 1042 { 1043 final List<String> urlStrings = 1044 new ArrayList<>(ldapURLsForSearchesExpectedToReturnEntries.size()); 1045 for (final LDAPURL url : ldapURLsForSearchesExpectedToReturnEntries) 1046 { 1047 urlStrings.add(url.toString()); 1048 } 1049 props.put(PROPERTY_SEARCH_URL, 1050 1051 Collections.<Object>unmodifiableList(urlStrings)); 1052 } 1053 1054 if (millisBetweenSearches != null) 1055 { 1056 props.put(PROPERTY_SEARCH_INTERVAL_MILLIS, 1057 Collections.<Object>singletonList(millisBetweenSearches)); 1058 } 1059 1060 if (searchTimeLimitMillis != null) 1061 { 1062 props.put(PROPERTY_SEARCH_TIME_LIMIT_MILLIS, 1063 Collections.<Object>singletonList(searchTimeLimitMillis)); 1064 } 1065 1066 if (totalDurationMillisForEachLDAPURL != null) 1067 { 1068 props.put(PROPERTY_SEARCH_DURATION_MILLIS, 1069 Collections.<Object>singletonList( 1070 totalDurationMillisForEachLDAPURL)); 1071 } 1072 1073 if (taskStateIfTimeoutIsEncountered != null) 1074 { 1075 props.put(PROPERTY_TIMEOUT_RETURN_STATE, 1076 Collections.<Object>singletonList(taskStateIfTimeoutIsEncountered)); 1077 } 1078 1079 return Collections.unmodifiableMap(props); 1080 } 1081}