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