001/* 002 * Copyright 2008-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-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.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.Debug; 036import com.unboundid.util.NotMutable; 037import com.unboundid.util.StaticUtils; 038import com.unboundid.util.ThreadSafety; 039import com.unboundid.util.ThreadSafetyLevel; 040import com.unboundid.util.Validator; 041 042import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 043 044 045 046/** 047 * This class defines a Directory Server task that can be used to generate 048 * and/or rebuild one or more indexes a Berkeley DB Java Edition backend. 049 * <BR> 050 * <BLOCKQUOTE> 051 * <B>NOTE:</B> This class, and other classes within the 052 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 053 * supported for use against Ping Identity, UnboundID, and 054 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 055 * for proprietary functionality or for external specifications that are not 056 * considered stable or mature enough to be guaranteed to work in an 057 * interoperable way with other types of LDAP servers. 058 * </BLOCKQUOTE> 059 * <BR> 060 * The properties that are available for use with this type of task include: 061 * <UL> 062 * <LI>The backend base DN for which to perform the index rebuild. This 063 * must be provided when scheduling a rebuild task.</LI> 064 * <LI>The names of the indexes to be built. At least one index name must be 065 * provided when scheduling a rebuild task.</LI> 066 * <LI>The maximum number of concurrent threads that should be used to perform 067 * the processing. A value of zero indicates that there is no limit.</LI> 068 * </UL> 069 070 */ 071@NotMutable() 072@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 073public final class RebuildTask 074 extends Task 075{ 076 /** 077 * The fully-qualified name of the Java class that is used for the rebuild 078 * task. 079 */ 080 static final String REBUILD_TASK_CLASS = 081 "com.unboundid.directory.server.tasks.RebuildTask"; 082 083 084 085 /** 086 * The name of the attribute used to specify the base DN for which to rebuild 087 * the specified indexes. 088 */ 089 private static final String ATTR_BASE_DN = "ds-task-rebuild-base-dn"; 090 091 092 093 /** 094 * The name of the attribute used to specify the names of the indexes to 095 * rebuild. 096 */ 097 private static final String ATTR_INDEX = "ds-task-rebuild-index"; 098 099 100 101 /** 102 * The name of the attribute used to specify the maximum number of concurrent 103 * threads to use to perform the rebuild. 104 */ 105 private static final String ATTR_MAX_THREADS = "ds-task-rebuild-max-threads"; 106 107 108 109 /** 110 * The name of the object class used in rebuild task entries. 111 */ 112 private static final String OC_REBUILD_TASK = "ds-task-rebuild"; 113 114 115 116 /** 117 * The task property for the base DN. 118 */ 119 private static final TaskProperty PROPERTY_BASE_DN = 120 new TaskProperty(ATTR_BASE_DN, INFO_DISPLAY_NAME_BASE_DN_REBUILD.get(), 121 INFO_DESCRIPTION_BASE_DN_REBUILD.get(), String.class, 122 true, false, false); 123 124 125 126 /** 127 * The task property for the index names. 128 */ 129 private static final TaskProperty PROPERTY_INDEX = 130 new TaskProperty(ATTR_INDEX, INFO_DISPLAY_NAME_INDEX_REBUILD.get(), 131 INFO_DESCRIPTION_INDEX_REBUILD.get(), String.class, 132 true, true, false); 133 134 135 136 /** 137 * The task property for the max threads value. 138 */ 139 private static final TaskProperty PROPERTY_MAX_THREADS = 140 new TaskProperty(ATTR_MAX_THREADS, 141 INFO_DISPLAY_NAME_MAX_THREADS_REBUILD.get(), 142 INFO_DESCRIPTION_MAX_THREADS_REBUILD.get(), Long.class, 143 false, false, true); 144 145 146 147 /** 148 * The serial version UID for this serializable class. 149 */ 150 private static final long serialVersionUID = 6015907901926792443L; 151 152 153 154 // The maximum number of threads to use to rebuild indexes. 155 private final int maxThreads; 156 157 // The base DN for which to rebuild indexes. 158 private final String baseDN; 159 160 // The names of the indexes to rebuild. 161 private final List<String> indexes; 162 163 164 165 /** 166 * Creates a new uninitialized rebuild task instance which should only be used 167 * for obtaining general information about this task, including the task name, 168 * description, and supported properties. Attempts to use a task created with 169 * this constructor for any other reason will likely fail. 170 */ 171 public RebuildTask() 172 { 173 baseDN = null; 174 maxThreads = -1; 175 indexes = null; 176 } 177 178 179 180 /** 181 * Creates a new rebuild task with the provided information. 182 * 183 * @param taskID The task ID to use for this task. If it is {@code null} 184 * then a UUID will be generated for use as the task ID. 185 * @param baseDN The base DN for which to rebuild the index. It must refer 186 * to a base DN for a Berkeley DB Java Edition backend. It 187 * must not be {@code null}. 188 * @param indexes A list containing the names of the indexes to rebuild. It 189 * must not be {@code null} or empty. 190 */ 191 public RebuildTask(final String taskID, final String baseDN, 192 final List<String> indexes) 193 { 194 this(taskID, baseDN, indexes, -1, null, null, null, null, null); 195 } 196 197 198 199 /** 200 * Creates a new rebuild task with the provided information. 201 * 202 * @param taskID The task ID to use for this task. If it is 203 * {@code null} then a UUID will be generated 204 * for use as the task ID. 205 * @param baseDN The base DN for which to rebuild the index. 206 * It must refer to a base DN for a Berkeley 207 * DB Java Edition backend. It must not be 208 * {@code null}. 209 * @param indexes A list containing the names of the indexes 210 * to rebuild. It must not be {@code null} or 211 * empty. 212 * @param maxThreads The maximum number of concurrent threads to 213 * use while performing the rebuild. A value 214 * less than or equal to zero indicates that 215 * there is no limit to the number of threads 216 * that may be used. 217 * @param scheduledStartTime The time that this task should start 218 * running. 219 * @param dependencyIDs The list of task IDs that will be required 220 * to complete before this task will be 221 * eligible to start. 222 * @param failedDependencyAction Indicates what action should be taken if 223 * any of the dependencies for this task do 224 * not complete successfully. 225 * @param notifyOnCompletion The list of e-mail addresses of individuals 226 * that should be notified when this task 227 * completes. 228 * @param notifyOnError The list of e-mail addresses of individuals 229 * that should be notified if this task does 230 * not complete successfully. 231 */ 232 public RebuildTask(final String taskID, final String baseDN, 233 final List<String> indexes, final int maxThreads, 234 final Date scheduledStartTime, 235 final List<String> dependencyIDs, 236 final FailedDependencyAction failedDependencyAction, 237 final List<String> notifyOnCompletion, 238 final List<String> notifyOnError) 239 { 240 this(taskID, baseDN, indexes, maxThreads, scheduledStartTime, dependencyIDs, 241 failedDependencyAction, null, notifyOnCompletion, null, notifyOnError, 242 null, null, null); 243 } 244 245 246 247 /** 248 * Creates a new rebuild task with the provided information. 249 * 250 * @param taskID The task ID to use for this task. If it is 251 * {@code null} then a UUID will be generated 252 * for use as the task ID. 253 * @param baseDN The base DN for which to rebuild the index. 254 * It must refer to a base DN for a Berkeley 255 * DB Java Edition backend. It must not be 256 * {@code null}. 257 * @param indexes A list containing the names of the indexes 258 * to rebuild. It must not be {@code null} or 259 * empty. 260 * @param maxThreads The maximum number of concurrent threads to 261 * use while performing the rebuild. A value 262 * less than or equal to zero indicates that 263 * there is no limit to the number of threads 264 * that may be used. 265 * @param scheduledStartTime The time that this task should start 266 * running. 267 * @param dependencyIDs The list of task IDs that will be required 268 * to complete before this task will be 269 * eligible to start. 270 * @param failedDependencyAction Indicates what action should be taken if 271 * any of the dependencies for this task do 272 * not complete successfully. 273 * @param notifyOnStart The list of e-mail addresses of individuals 274 * that should be notified when this task 275 * starts running. 276 * @param notifyOnCompletion The list of e-mail addresses of individuals 277 * that should be notified when this task 278 * completes. 279 * @param notifyOnSuccess The list of e-mail addresses of individuals 280 * that should be notified if this task 281 * completes successfully. 282 * @param notifyOnError The list of e-mail addresses of individuals 283 * that should be notified if this task does 284 * not complete successfully. 285 * @param alertOnStart Indicates whether the server should send an 286 * alert notification when this task starts. 287 * @param alertOnSuccess Indicates whether the server should send an 288 * alert notification if this task completes 289 * successfully. 290 * @param alertOnError Indicates whether the server should send an 291 * alert notification if this task fails to 292 * complete successfully. 293 */ 294 public RebuildTask(final String taskID, final String baseDN, 295 final List<String> indexes, final int maxThreads, 296 final Date scheduledStartTime, 297 final List<String> dependencyIDs, 298 final FailedDependencyAction failedDependencyAction, 299 final List<String> notifyOnStart, 300 final List<String> notifyOnCompletion, 301 final List<String> notifyOnSuccess, 302 final List<String> notifyOnError, 303 final Boolean alertOnStart, final Boolean alertOnSuccess, 304 final Boolean alertOnError) 305 { 306 super(taskID, REBUILD_TASK_CLASS, scheduledStartTime, dependencyIDs, 307 failedDependencyAction, notifyOnStart, notifyOnCompletion, 308 notifyOnSuccess, notifyOnError, alertOnStart, alertOnSuccess, 309 alertOnError); 310 311 Validator.ensureNotNull(baseDN, indexes); 312 Validator.ensureFalse(indexes.isEmpty(), 313 "RebuildTask.indexes must not be empty."); 314 315 this.baseDN = baseDN; 316 this.indexes = Collections.unmodifiableList(indexes); 317 this.maxThreads = maxThreads; 318 } 319 320 321 322 /** 323 * Creates a new rebuild task from the provided entry. 324 * 325 * @param entry The entry to use to create this rebuild task. 326 * 327 * @throws TaskException If the provided entry cannot be parsed as a rebuild 328 * task entry. 329 */ 330 public RebuildTask(final Entry entry) 331 throws TaskException 332 { 333 super(entry); 334 335 336 // Get the base DN. It must be present. 337 baseDN = entry.getAttributeValue(ATTR_BASE_DN); 338 if (baseDN == null) 339 { 340 throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get( 341 getTaskEntryDN())); 342 } 343 344 345 // Get the names of the indexes to rebuild. It must be present. 346 final String[] indexArray = entry.getAttributeValues(ATTR_INDEX); 347 if ((indexArray == null) || (indexArray.length == 0)) 348 { 349 throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get( 350 getTaskEntryDN())); 351 } 352 else 353 { 354 indexes = Collections.unmodifiableList(Arrays.asList(indexArray)); 355 } 356 357 358 // Get the maximum number of threads to use. 359 final String threadsStr = entry.getAttributeValue(ATTR_MAX_THREADS); 360 if (threadsStr == null) 361 { 362 maxThreads = -1; 363 } 364 else 365 { 366 try 367 { 368 maxThreads = Integer.parseInt(threadsStr); 369 } 370 catch (final Exception e) 371 { 372 Debug.debugException(e); 373 throw new TaskException(ERR_REBUILD_TASK_INVALID_MAX_THREADS.get( 374 getTaskEntryDN(), threadsStr), e); 375 } 376 } 377 } 378 379 380 381 /** 382 * Creates a new rebuild task from the provided set of task properties. 383 * 384 * @param properties The set of task properties and their corresponding 385 * values to use for the task. It must not be 386 * {@code null}. 387 * 388 * @throws TaskException If the provided set of properties cannot be used to 389 * create a valid rebuild task. 390 */ 391 public RebuildTask(final Map<TaskProperty,List<Object>> properties) 392 throws TaskException 393 { 394 super(REBUILD_TASK_CLASS, properties); 395 396 long t = -1; 397 String b = null; 398 String[] i = null; 399 400 for (final Map.Entry<TaskProperty,List<Object>> entry : 401 properties.entrySet()) 402 { 403 final TaskProperty p = entry.getKey(); 404 final String attrName = p.getAttributeName(); 405 final List<Object> values = entry.getValue(); 406 407 if (attrName.equalsIgnoreCase(ATTR_BASE_DN)) 408 { 409 b = parseString(p, values, b); 410 } 411 else if (attrName.equalsIgnoreCase(ATTR_INDEX)) 412 { 413 i = parseStrings(p, values, i); 414 } 415 else if (attrName.equalsIgnoreCase(ATTR_MAX_THREADS)) 416 { 417 t = parseLong(p, values, t); 418 } 419 } 420 421 if (b == null) 422 { 423 throw new TaskException(ERR_REBUILD_TASK_NO_BASE_DN.get( 424 getTaskEntryDN())); 425 } 426 427 if (i == null) 428 { 429 throw new TaskException(ERR_REBUILD_TASK_NO_INDEXES.get( 430 getTaskEntryDN())); 431 } 432 433 baseDN = b; 434 indexes = Collections.unmodifiableList(Arrays.asList(i)); 435 maxThreads = (int) t; 436 } 437 438 439 440 /** 441 * {@inheritDoc} 442 */ 443 @Override() 444 public String getTaskName() 445 { 446 return INFO_TASK_NAME_REBUILD.get(); 447 } 448 449 450 451 /** 452 * {@inheritDoc} 453 */ 454 @Override() 455 public String getTaskDescription() 456 { 457 return INFO_TASK_DESCRIPTION_REBUILD.get(); 458 } 459 460 461 462 /** 463 * Retrieves the base DN for which to rebuild the specified indexes. 464 * 465 * @return The base DN for which to rebuild the specified indexes. 466 */ 467 public String getBaseDN() 468 { 469 return baseDN; 470 } 471 472 473 474 /** 475 * Retrieves the names of the indexes to be rebuilt. 476 * 477 * @return The names of the indexes to be rebuilt. 478 */ 479 public List<String> getIndexNames() 480 { 481 return indexes; 482 } 483 484 485 486 /** 487 * Retrieves the maximum number of concurrent threads that should be used when 488 * rebuilding the indexes. 489 * 490 * @return The maximum number of concurrent threads that should be used when 491 * rebuilding the indexes, or a value less than or equal to zero if 492 * there is no limit on the number of threads that may be used. 493 */ 494 public int getMaxRebuildThreads() 495 { 496 return maxThreads; 497 } 498 499 500 501 /** 502 * {@inheritDoc} 503 */ 504 @Override() 505 protected List<String> getAdditionalObjectClasses() 506 { 507 return Collections.singletonList(OC_REBUILD_TASK); 508 } 509 510 511 512 /** 513 * {@inheritDoc} 514 */ 515 @Override() 516 protected List<Attribute> getAdditionalAttributes() 517 { 518 final ArrayList<Attribute> attrs = new ArrayList<>(3); 519 520 attrs.add(new Attribute(ATTR_BASE_DN, baseDN)); 521 attrs.add(new Attribute(ATTR_INDEX, indexes)); 522 523 if (maxThreads > 0) 524 { 525 attrs.add(new Attribute(ATTR_MAX_THREADS, String.valueOf(maxThreads))); 526 } 527 528 return attrs; 529 } 530 531 532 533 /** 534 * {@inheritDoc} 535 */ 536 @Override() 537 public List<TaskProperty> getTaskSpecificProperties() 538 { 539 final List<TaskProperty> propList = Arrays.asList( 540 PROPERTY_BASE_DN, 541 PROPERTY_INDEX, 542 PROPERTY_MAX_THREADS); 543 544 return Collections.unmodifiableList(propList); 545 } 546 547 548 549 /** 550 * {@inheritDoc} 551 */ 552 @Override() 553 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 554 { 555 final LinkedHashMap<TaskProperty,List<Object>> props = 556 new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); 557 558 props.put(PROPERTY_BASE_DN, 559 Collections.<Object>singletonList(baseDN)); 560 561 props.put(PROPERTY_INDEX, 562 Collections.<Object>unmodifiableList(indexes)); 563 564 props.put(PROPERTY_MAX_THREADS, 565 Collections.<Object>singletonList((long) maxThreads)); 566 567 props.putAll(super.getTaskPropertyValues()); 568 return Collections.unmodifiableMap(props); 569 } 570}