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 }