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