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