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