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