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