001 /* 002 * Copyright 2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2015 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.ldap.sdk.unboundidds.tasks; 022 023 024 025 import java.util.ArrayList; 026 import java.util.Arrays; 027 import java.util.Collections; 028 import java.util.Date; 029 import java.util.LinkedHashMap; 030 import java.util.List; 031 import java.util.Map; 032 033 import com.unboundid.ldap.sdk.Attribute; 034 import com.unboundid.ldap.sdk.Entry; 035 import com.unboundid.util.NotMutable; 036 import com.unboundid.util.ThreadSafety; 037 import com.unboundid.util.ThreadSafetyLevel; 038 039 import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 040 import static com.unboundid.util.Validator.*; 041 042 043 044 /** 045 * <BLOCKQUOTE> 046 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 047 * LDAP SDK for Java. It is not available for use in applications that 048 * include only the Standard Edition of the LDAP SDK, and is not supported for 049 * use in conjunction with non-UnboundID products. 050 * </BLOCKQUOTE> 051 * This class defines a Directory Proxy Server task that can be used to reload 052 * the contents of the global index. The properties that are available for use 053 * with this type of task include: 054 * <UL> 055 * <LI>The base DN for the entry-balancing request processor.</LI> 056 * <LI>An optional set of attributes for which to reload the index 057 * information.</LI> 058 * <LI>A flag indicating whether to perform the reload in the background.</LI> 059 * <LI>A flag indicating whether to reload entries from backend Directory 060 * Server instances rather than a peer Directory Proxy Server 061 * instance.</LI> 062 * <LI>An optional maximum number of entries per second to access when 063 * priming.</LI> 064 * </UL> 065 */ 066 @NotMutable() 067 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 068 public final class ReloadGlobalIndexTask 069 extends Task 070 { 071 /** 072 * The fully-qualified name of the Java class that is used for the re-encode 073 * entries task. 074 */ 075 static final String RELOAD_GLOBAL_INDEX_TASK_CLASS = 076 "com.unboundid.directory.proxy.tasks.ReloadTask"; 077 078 079 080 /** 081 * The name of the attribute used to indicate whether the reload should be 082 * done in the background. 083 */ 084 private static final String ATTR_BACKGROUND_RELOAD = 085 "ds-task-reload-background"; 086 087 088 089 /** 090 * The name of the attribute used to specify the base DN for the 091 * entry-balancing request processor. 092 */ 093 private static final String ATTR_BASE_DN = "ds-task-reload-base-dn"; 094 095 096 097 /** 098 * The name of the attribute used to specify the names of the attributes for 099 * which to reload the indexes. 100 */ 101 private static final String ATTR_INDEX_NAME = "ds-task-reload-index-name"; 102 103 104 105 /** 106 * The name of the attribute used to specify a target rate limit for the 107 * maximum number of entries per second. 108 */ 109 private static final String ATTR_MAX_ENTRIES_PER_SECOND = 110 "ds-task-search-entry-per-second"; 111 112 113 114 /** 115 * The name of the attribute used to indicate whether the data should be 116 * loaded from backend Directory Server instances rather than a peer Directory 117 * Proxy Server instance. 118 */ 119 private static final String ATTR_RELOAD_FROM_DS = "ds-task-reload-from-ds"; 120 121 122 123 /** 124 * The name of the object class used in reload global index task entries. 125 */ 126 private static final String OC_RELOAD_GLOBAL_INDEX_TASK = 127 "ds-task-reload-index"; 128 129 130 131 /** 132 * The task property that will be used for the request processor base DN. 133 */ 134 static final TaskProperty PROPERTY_BACKGROUND_RELOAD = new TaskProperty( 135 ATTR_BACKGROUND_RELOAD, 136 INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_BACKGROUND.get(), 137 INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_BACKGROUND.get(), Boolean.class, 138 false, false, false); 139 140 141 142 /** 143 * The task property that will be used for the request processor base DN. 144 */ 145 static final TaskProperty PROPERTY_BASE_DN = new TaskProperty( 146 ATTR_BASE_DN, INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_BASE_DN.get(), 147 INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_BASE_DN.get(), String.class, true, 148 false, false); 149 150 151 152 /** 153 * The task property that will be used for the request processor base DN. 154 */ 155 static final TaskProperty PROPERTY_INDEX_NAME = new TaskProperty( 156 ATTR_INDEX_NAME, INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_ATTR_NAME.get(), 157 INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_ATTR_NAME.get(), String.class, 158 false, true, false); 159 160 161 162 /** 163 * The task property that will be used for the request processor base DN. 164 */ 165 static final TaskProperty PROPERTY_MAX_ENTRIES_PER_SECOND = new TaskProperty( 166 ATTR_MAX_ENTRIES_PER_SECOND, 167 INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_MAX_ENTRIES_PER_SECOND.get(), 168 INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_MAX_ENTRIES_PER_SECOND.get(), 169 Long.class, false, false, false); 170 171 172 173 /** 174 * The task property that will be used for the request processor base DN. 175 */ 176 static final TaskProperty PROPERTY_RELOAD_FROM_DS = new TaskProperty( 177 ATTR_RELOAD_FROM_DS, 178 INFO_DISPLAY_NAME_RELOAD_GLOBAL_INDEX_RELOAD_FROM_DS.get(), 179 INFO_DESCRIPTION_RELOAD_GLOBAL_INDEX_RELOAD_FROM_DS.get(), Boolean.class, 180 false, false, false); 181 182 183 184 /** 185 * The serial version UID for this serializable class. 186 */ 187 private static final long serialVersionUID = 9152807987055252560L; 188 189 190 191 // Indicates whether to reload from backend Directory Server instances. 192 private final Boolean reloadFromDS; 193 194 // Indicates whether to reload in the background. 195 private final Boolean reloadInBackground; 196 197 // The names of the indexes to reload. 198 private final List<String> indexNames; 199 200 // The target maximum rate limit to use when loading entry data. 201 private final Long maxEntriesPerSecond; 202 203 // The base DN for the entry-balancing request processor. 204 private final String baseDN; 205 206 207 208 /** 209 * Creates a new uninitialized reload global index task instance which should 210 * only be used for obtaining general information about this task, including 211 * the task name, description, and supported properties. Attempts to use a 212 * task created with this constructor for any other reason will likely fail. 213 */ 214 public ReloadGlobalIndexTask() 215 { 216 reloadFromDS = null; 217 reloadInBackground = null; 218 indexNames = null; 219 maxEntriesPerSecond = null; 220 baseDN = null; 221 } 222 223 224 225 226 /** 227 * Creates a new reload global index task with the provided information. 228 * 229 * @param taskID The task ID to use for this task. If it is 230 * {@code null} then a UUID will be generated for 231 * use as the task ID. 232 * @param baseDN The base DN of the entry-balancing request 233 * processor for which to reload index 234 * information. 235 * @param indexNames The names of the attributes for which to 236 * reload index data. This may be {@code null} 237 * or empty to indicate that all indexes should 238 * be reloaded. 239 * @param reloadFromDS Indicates whether to load index data from 240 * backend Directory Server instances rather than 241 * a peer Directory Proxy Server instance. This 242 * may be {@code null} to indicate that the 243 * Directory Proxy Server should automatically 244 * select the appropriate source for obtaining 245 * index data. 246 * @param reloadInBackground Indicates whether to perform the reload in 247 * the background, so that the task completes 248 * immediately. 249 * @param maxEntriesPerSecond The maximum target rate at which to reload 250 * index data (in entries per second). A value 251 * of zero indicates no limit. A value of 252 * {@code null} indicates that the Directory 253 * Proxy Server should attempt to determine the 254 * limit based on its configuration. 255 */ 256 public ReloadGlobalIndexTask(final String taskID, final String baseDN, 257 final List<String> indexNames, 258 final Boolean reloadFromDS, 259 final Boolean reloadInBackground, 260 final Long maxEntriesPerSecond) 261 { 262 this(taskID, baseDN, indexNames, reloadFromDS, reloadInBackground, 263 maxEntriesPerSecond, null, null, null, null, null); 264 } 265 266 267 268 /** 269 * Creates a new reload global index task with the provided information. 270 * 271 * @param taskID The task ID to use for this task. If it is 272 * {@code null} then a UUID will be generated 273 * for use as the task ID. 274 * @param baseDN The base DN of the entry-balancing request 275 * processor for which to reload index 276 * information. 277 * @param indexNames The names of the attributes for which to 278 * reload index data. This may be 279 * {@code null} or empty to indicate that all 280 * indexes should be reloaded. 281 * @param reloadFromDS Indicates whether to load index data from 282 * backend Directory Server instances rather 283 * than a peer Directory Proxy Server 284 * instance. This may be {@code null} to 285 * indicate that the Directory Proxy Server 286 * should automatically select the appropriate 287 * source for obtaining index data. 288 * @param reloadInBackground Indicates whether to perform the reload in 289 * the background, so that the task completes 290 * immediately. 291 * @param maxEntriesPerSecond The maximum target rate at which to reload 292 * index data (in entries per second). A 293 * value of zero indicates no limit. A value 294 * of {@code null} indicates that the 295 * Directory Proxy Server should attempt to 296 * determine the limit based on its 297 * configuration. 298 * @param scheduledStartTime The time that this task should start 299 * running. 300 * @param dependencyIDs The list of task IDs that will be required 301 * to complete before this task will be 302 * eligible to start. 303 * @param failedDependencyAction Indicates what action should be taken if 304 * any of the dependencies for this task do 305 * not complete successfully. 306 * @param notifyOnCompletion The list of e-mail addresses of individuals 307 * that should be notified when this task 308 * completes. 309 * @param notifyOnError The list of e-mail addresses of individuals 310 * that should be notified if this task does 311 * not complete successfully. 312 */ 313 public ReloadGlobalIndexTask(final String taskID, final String baseDN, 314 final List<String> indexNames, final Boolean reloadFromDS, 315 final Boolean reloadInBackground, final Long maxEntriesPerSecond, 316 final Date scheduledStartTime, 317 final List<String> dependencyIDs, 318 final FailedDependencyAction failedDependencyAction, 319 final List<String> notifyOnCompletion, 320 final List<String> notifyOnError) 321 { 322 super(taskID, RELOAD_GLOBAL_INDEX_TASK_CLASS, scheduledStartTime, 323 dependencyIDs, failedDependencyAction, notifyOnCompletion, 324 notifyOnError); 325 326 ensureNotNull(baseDN); 327 328 this.baseDN = baseDN; 329 this.reloadFromDS = reloadFromDS; 330 this.reloadInBackground = reloadInBackground; 331 this.maxEntriesPerSecond = maxEntriesPerSecond; 332 333 if (indexNames == null) 334 { 335 this.indexNames = Collections.emptyList(); 336 } 337 else 338 { 339 this.indexNames = Collections.unmodifiableList( 340 new ArrayList<String>(indexNames)); 341 } 342 } 343 344 345 346 /** 347 * Creates a new reload global index task from the provided entry. 348 * 349 * @param entry The entry to use to create this reload global index task. 350 * 351 * @throws TaskException If the provided entry cannot be parsed as a reload 352 * global index task entry. 353 */ 354 public ReloadGlobalIndexTask(final Entry entry) 355 throws TaskException 356 { 357 super(entry); 358 359 // Get the base DN. It must be present. 360 baseDN = entry.getAttributeValue(ATTR_BASE_DN); 361 if (baseDN == null) 362 { 363 throw new TaskException( 364 ERR_RELOAD_GLOBAL_INDEX_MISSING_REQUIRED_ATTR.get(ATTR_BASE_DN)); 365 } 366 367 // Get the names of the indexes to reload. It may be empty or null. 368 final String[] nameArray = entry.getAttributeValues(ATTR_INDEX_NAME); 369 if ((nameArray == null) || (nameArray.length == 0)) 370 { 371 indexNames = Collections.emptyList(); 372 } 373 else 374 { 375 indexNames = Collections.unmodifiableList(Arrays.asList(nameArray)); 376 } 377 378 // Get the flag indicating whether to reload from backend Directory Server 379 // instances. 380 reloadFromDS = entry.getAttributeValueAsBoolean(ATTR_RELOAD_FROM_DS); 381 382 // Get the flag indicating whether to reload in a background thread. 383 reloadInBackground = 384 entry.getAttributeValueAsBoolean(ATTR_BACKGROUND_RELOAD); 385 386 // Get the value specifying the maximum reload rate in entries per second. 387 maxEntriesPerSecond = 388 entry.getAttributeValueAsLong(ATTR_MAX_ENTRIES_PER_SECOND); 389 } 390 391 392 393 /** 394 * Creates a new reload global index task from the provided set of task 395 * properties. 396 * 397 * @param properties The set of task properties and their corresponding 398 * values to use for the task. It must not be 399 * {@code null}. 400 * 401 * @throws TaskException If the provided set of properties cannot be used to 402 * create a valid reload global index task. 403 */ 404 public ReloadGlobalIndexTask(final Map<TaskProperty,List<Object>> properties) 405 throws TaskException 406 { 407 super(RELOAD_GLOBAL_INDEX_TASK_CLASS, properties); 408 409 final List<String> attrs = new ArrayList<String>(10); 410 Boolean background = null; 411 Boolean fromDS = null; 412 Long maxPerSecond = null; 413 String baseDNStr = null; 414 415 for (final Map.Entry<TaskProperty,List<Object>> e : properties.entrySet()) 416 { 417 final TaskProperty p = e.getKey(); 418 final String attrName = p.getAttributeName(); 419 final List<Object> values = e.getValue(); 420 421 if (attrName.equalsIgnoreCase(ATTR_BASE_DN)) 422 { 423 baseDNStr = parseString(p, values, null); 424 } 425 else if (attrName.equalsIgnoreCase(ATTR_INDEX_NAME)) 426 { 427 final String[] nameArray = parseStrings(p, values, null); 428 if (nameArray != null) 429 { 430 attrs.addAll(Arrays.asList(nameArray)); 431 } 432 } 433 else if (attrName.equalsIgnoreCase(ATTR_RELOAD_FROM_DS)) 434 { 435 fromDS = parseBoolean(p, values, null); 436 } 437 else if (attrName.equalsIgnoreCase(ATTR_BACKGROUND_RELOAD)) 438 { 439 background = parseBoolean(p, values, null); 440 } 441 else if (attrName.equalsIgnoreCase(ATTR_MAX_ENTRIES_PER_SECOND)) 442 { 443 maxPerSecond = parseLong(p, values, null); 444 } 445 } 446 447 if (baseDNStr == null) 448 { 449 throw new TaskException( 450 ERR_RELOAD_GLOBAL_INDEX_MISSING_REQUIRED_PROPERTY.get(ATTR_BASE_DN)); 451 } 452 453 baseDN = baseDNStr; 454 indexNames = Collections.unmodifiableList(attrs); 455 reloadFromDS = fromDS; 456 reloadInBackground = background; 457 maxEntriesPerSecond = maxPerSecond; 458 } 459 460 461 462 /** 463 * {@inheritDoc} 464 */ 465 @Override() 466 public String getTaskName() 467 { 468 return INFO_TASK_NAME_RELOAD_GLOBAL_INDEX.get(); 469 } 470 471 472 473 /** 474 * {@inheritDoc} 475 */ 476 @Override() 477 public String getTaskDescription() 478 { 479 return INFO_TASK_DESCRIPTION_RELOAD_GLOBAL_INDEX.get(); 480 } 481 482 483 484 /** 485 * Retrieves the base DN of the entry-balancing request processor for which to 486 * reload index data. 487 * 488 * @return The base DN of the entry-balancing request processor for which to 489 * reload index data. 490 */ 491 public String getBaseDN() 492 { 493 return baseDN; 494 } 495 496 497 498 /** 499 * Retrieves the names of the indexes to be reloaded. 500 * 501 * @return The names of the indexes to be reloaded, or an empty list if the 502 * Directory Proxy Server should reload all indexes. 503 */ 504 public List<String> getIndexNames() 505 { 506 return indexNames; 507 } 508 509 510 511 /** 512 * Indicates whether to reload index information from backend Directory 513 * Servers rather than a peer Directory Proxy Server. 514 * 515 * @return {@code true} if the index information should be reloaded from 516 * backend Directory Servers, {@code false} if the index information 517 * should be reloaded from a peer Directory Proxy Server instance, or 518 * {@code null} if the Directory Proxy Server should automatically 519 * determine the reload data source. 520 */ 521 public Boolean reloadFromDS() 522 { 523 return reloadFromDS; 524 } 525 526 527 528 /** 529 * Indicates whether to perform the index reload processing in the background. 530 * 531 * @return {@code true} if the index reload processing should be performed 532 * in the background (so that the task completes immediately), 533 * {@code false} if not, or {@code null} if the Directory Proxy 534 * Server should determine whether to perform the reload in the 535 * background. 536 */ 537 public Boolean reloadInBackground() 538 { 539 return reloadInBackground; 540 } 541 542 543 544 /** 545 * Retrieves the maximum reload rate in entries per second, if defined. 546 * 547 * @return The maximum rate at which to reload index data, in entries per 548 * second, zero if no limit should be imposed, or {@code null} if the 549 * Directory Proxy Server should determine the maximum reload rate. 550 */ 551 public Long getMaxEntriesPerSecond() 552 { 553 return maxEntriesPerSecond; 554 } 555 556 557 558 /** 559 * {@inheritDoc} 560 */ 561 @Override() 562 protected List<String> getAdditionalObjectClasses() 563 { 564 return Arrays.asList(OC_RELOAD_GLOBAL_INDEX_TASK); 565 } 566 567 568 569 /** 570 * {@inheritDoc} 571 */ 572 @Override() 573 protected List<Attribute> getAdditionalAttributes() 574 { 575 final ArrayList<Attribute> attrList = new ArrayList<Attribute>(5); 576 577 attrList.add(new Attribute(ATTR_BASE_DN, baseDN)); 578 579 if (! indexNames.isEmpty()) 580 { 581 attrList.add(new Attribute(ATTR_INDEX_NAME, indexNames)); 582 } 583 584 if (reloadFromDS != null) 585 { 586 attrList.add(new Attribute(ATTR_RELOAD_FROM_DS, 587 String.valueOf(reloadFromDS))); 588 } 589 590 if (reloadInBackground != null) 591 { 592 attrList.add(new Attribute(ATTR_BACKGROUND_RELOAD, 593 String.valueOf(reloadInBackground))); 594 } 595 596 if (maxEntriesPerSecond != null) 597 { 598 attrList.add(new Attribute(ATTR_MAX_ENTRIES_PER_SECOND, 599 String.valueOf(maxEntriesPerSecond))); 600 } 601 602 return attrList; 603 } 604 605 606 607 /** 608 * {@inheritDoc} 609 */ 610 @Override() 611 public List<TaskProperty> getTaskSpecificProperties() 612 { 613 return Collections.unmodifiableList(Arrays.asList( 614 PROPERTY_BASE_DN, 615 PROPERTY_INDEX_NAME, 616 PROPERTY_RELOAD_FROM_DS, 617 PROPERTY_BACKGROUND_RELOAD, 618 PROPERTY_MAX_ENTRIES_PER_SECOND)); 619 } 620 621 622 623 /** 624 * {@inheritDoc} 625 */ 626 @Override() 627 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 628 { 629 final LinkedHashMap<TaskProperty,List<Object>> props = 630 new LinkedHashMap<TaskProperty,List<Object>>(15); 631 632 props.put(PROPERTY_BASE_DN, 633 Collections.<Object>unmodifiableList(Arrays.asList(baseDN))); 634 props.put(PROPERTY_INDEX_NAME, 635 Collections.<Object>unmodifiableList(indexNames)); 636 637 if (reloadFromDS == null) 638 { 639 props.put(PROPERTY_RELOAD_FROM_DS, 640 Collections.emptyList()); 641 } 642 else 643 { 644 props.put(PROPERTY_RELOAD_FROM_DS, 645 Collections.<Object>unmodifiableList(Arrays.asList(reloadFromDS))); 646 } 647 648 if (reloadInBackground == null) 649 { 650 props.put(PROPERTY_BACKGROUND_RELOAD, 651 Collections.emptyList()); 652 } 653 else 654 { 655 props.put(PROPERTY_BACKGROUND_RELOAD, 656 Collections.<Object>unmodifiableList(Arrays.asList( 657 reloadInBackground))); 658 } 659 660 if (maxEntriesPerSecond == null) 661 { 662 props.put(PROPERTY_MAX_ENTRIES_PER_SECOND, 663 Collections.emptyList()); 664 } 665 else 666 { 667 props.put(PROPERTY_MAX_ENTRIES_PER_SECOND, 668 Collections.<Object>unmodifiableList( 669 Arrays.asList(maxEntriesPerSecond))); 670 } 671 672 props.putAll(super.getTaskPropertyValues()); 673 return Collections.unmodifiableMap(props); 674 } 675 }