001/* 002 * Copyright 2008-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2008-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) 2008-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; 056import com.unboundid.util.Validator; 057 058import static com.unboundid.ldap.sdk.unboundidds.tasks.TaskMessages.*; 059 060 061 062/** 063 * This class defines a Directory Server task that can be used to invoke 064 * third-party code created using the UnboundID Server SDK. 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 fully-qualified name of the Java class providing the logic for the 079 * third-party task. This must be provided.</LI> 080 * <LI>A list of the arguments to use for the task.</LI> 081 * </UL> 082 */ 083@NotMutable() 084@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 085public final class ThirdPartyTask 086 extends Task 087{ 088 /** 089 * The fully-qualified name of the Java class that is used for the core 090 * third-party task. 091 */ 092 @NotNull static final String THIRD_PARTY_TASK_CLASS = 093 "com.unboundid.directory.sdk.extensions.ThirdPartyTask"; 094 095 096 097 /** 098 * The name of the attribute used to specify the fully-qualified name of the 099 * Java class providing the task logic. 100 */ 101 @NotNull private static final String ATTR_THIRD_PARTY_TASK_CLASS = 102 "ds-third-party-task-java-class"; 103 104 105 106 /** 107 * The name of the attribute used to provide arguments for the task. 108 */ 109 @NotNull private static final String ATTR_THIRD_PARTY_TASK_ARGUMENT = 110 "ds-third-party-task-argument"; 111 112 113 114 /** 115 * The name of the object class used in third-party task entries. 116 */ 117 @NotNull private static final String OC_THIRD_PARTY_TASK = 118 "ds-third-party-task"; 119 120 121 122 /** 123 * The task property that will be used for the task class. 124 */ 125 @NotNull static final TaskProperty PROPERTY_TASK_CLASS = 126 new TaskProperty(ATTR_THIRD_PARTY_TASK_CLASS, 127 INFO_DISPLAY_NAME_THIRD_PARTY_TASK_CLASS.get(), 128 INFO_DESCRIPTION_THIRD_PARTY_TASK_CLASS.get(), String.class, true, 129 false, false); 130 131 132 133 /** 134 * The task property that will be used for the task arguments. 135 */ 136 @NotNull static final TaskProperty PROPERTY_TASK_ARG = 137 new TaskProperty(ATTR_THIRD_PARTY_TASK_ARGUMENT, 138 INFO_DISPLAY_NAME_THIRD_PARTY_TASK_ARG.get(), 139 INFO_DESCRIPTION_THIRD_PARTY_TASK_ARG.get(), String.class, false, 140 true, false); 141 142 143 144 /** 145 * The serial version UID for this serializable class. 146 */ 147 private static final long serialVersionUID = 8448474409066265724L; 148 149 150 151 // A list of the arguments for the task. 152 @NotNull private final List<String> taskArguments; 153 154 // The name of the java class providing the logic for the third-party task. 155 @NotNull private final String taskClassName; 156 157 158 159 /** 160 * Creates a new uninitialized third-party task instance which should only 161 * be used for obtaining general information about this task, including the 162 * task name, description, and supported properties. Attempts to use a task 163 * created with this constructor for any other reason will likely fail. 164 */ 165 public ThirdPartyTask() 166 { 167 taskArguments = null; 168 taskClassName = null; 169 } 170 171 172 173 /** 174 * Creates a new third-party task with the provided information. 175 * 176 * @param taskID The task ID to use for this task. If it is 177 * {@code null} then a UUID will be generated for use 178 * as the task ID. 179 * @param taskClassName The fully-qualified name of the Java class providing 180 * the logic for the task. It must not be 181 * {@code null}. 182 * @param taskArguments A list of the arguments for the task, in the form 183 * name=value. It may be {@code null} or empty if 184 * there should not be any arguments. 185 */ 186 public ThirdPartyTask(@Nullable final String taskID, 187 @NotNull final String taskClassName, 188 @Nullable final List<String> taskArguments) 189 { 190 this(taskID, taskClassName, taskArguments, null, null, null, null, null); 191 } 192 193 194 195 /** 196 * Creates a new third-party task with the provided information. 197 * 198 * @param taskID The task ID to use for this task. If it is 199 * {@code null} then a UUID will be generated 200 * for use as the task ID. 201 * @param taskClassName The fully-qualified name of the Java class 202 * providing the logic for the task. It must 203 * not be {@code null}. 204 * @param taskArguments A list of the arguments for the task, in 205 * the form name=value. It may be 206 * {@code null} or empty if there should not 207 * be any arguments. 208 * @param scheduledStartTime The time that this task should start 209 * running. 210 * @param dependencyIDs The list of task IDs that will be required 211 * to complete before this task will be 212 * eligible to start. 213 * @param failedDependencyAction Indicates what action should be taken if 214 * any of the dependencies for this task do 215 * not complete successfully. 216 * @param notifyOnCompletion The list of e-mail addresses of individuals 217 * that should be notified when this task 218 * completes. 219 * @param notifyOnError The list of e-mail addresses of individuals 220 * that should be notified if this task does 221 * not complete successfully. 222 */ 223 public ThirdPartyTask(@Nullable final String taskID, 224 @NotNull final String taskClassName, 225 @Nullable final List<String> taskArguments, 226 @Nullable final Date scheduledStartTime, 227 @Nullable final List<String> dependencyIDs, 228 @Nullable final FailedDependencyAction failedDependencyAction, 229 @Nullable final List<String> notifyOnCompletion, 230 @Nullable final List<String> notifyOnError) 231 { 232 this(taskID, taskClassName, taskArguments, scheduledStartTime, 233 dependencyIDs, failedDependencyAction, null, notifyOnCompletion, 234 null, notifyOnError, null, null, null); 235 } 236 237 238 239 /** 240 * Creates a new third-party task with the provided information. 241 * 242 * @param taskID The task ID to use for this task. If it is 243 * {@code null} then a UUID will be generated 244 * for use as the task ID. 245 * @param taskClassName The fully-qualified name of the Java class 246 * providing the logic for the task. It must 247 * not be {@code null}. 248 * @param taskArguments A list of the arguments for the task, in 249 * the form name=value. It may be 250 * {@code null} or empty if there should not 251 * be any arguments. 252 * @param scheduledStartTime The time that this task should start 253 * running. 254 * @param dependencyIDs The list of task IDs that will be required 255 * to complete before this task will be 256 * eligible to start. 257 * @param failedDependencyAction Indicates what action should be taken if 258 * any of the dependencies for this task do 259 * not complete successfully. 260 * @param notifyOnStart The list of e-mail addresses of individuals 261 * that should be notified when this task 262 * starts running. 263 * @param notifyOnCompletion The list of e-mail addresses of individuals 264 * that should be notified when this task 265 * completes. 266 * @param notifyOnSuccess The list of e-mail addresses of individuals 267 * that should be notified if this task 268 * completes successfully. 269 * @param notifyOnError The list of e-mail addresses of individuals 270 * that should be notified if this task does 271 * not complete successfully. 272 * @param alertOnStart Indicates whether the server should send an 273 * alert notification when this task starts. 274 * @param alertOnSuccess Indicates whether the server should send an 275 * alert notification if this task completes 276 * successfully. 277 * @param alertOnError Indicates whether the server should send an 278 * alert notification if this task fails to 279 * complete successfully. 280 */ 281 public ThirdPartyTask(@Nullable final String taskID, 282 @NotNull final String taskClassName, 283 @Nullable final List<String> taskArguments, 284 @Nullable final Date scheduledStartTime, 285 @Nullable final List<String> dependencyIDs, 286 @Nullable final FailedDependencyAction failedDependencyAction, 287 @Nullable final List<String> notifyOnStart, 288 @Nullable final List<String> notifyOnCompletion, 289 @Nullable final List<String> notifyOnSuccess, 290 @Nullable final List<String> notifyOnError, 291 @Nullable final Boolean alertOnStart, 292 @Nullable final Boolean alertOnSuccess, 293 @Nullable final Boolean alertOnError) 294 { 295 super(taskID, THIRD_PARTY_TASK_CLASS, scheduledStartTime, 296 dependencyIDs, failedDependencyAction, notifyOnStart, 297 notifyOnCompletion, notifyOnSuccess, notifyOnError, alertOnStart, 298 alertOnSuccess, alertOnError); 299 300 Validator.ensureNotNull(taskClassName); 301 302 this.taskClassName = taskClassName; 303 304 if (taskArguments == null) 305 { 306 this.taskArguments = Collections.emptyList(); 307 } 308 else 309 { 310 this.taskArguments = Collections.unmodifiableList(taskArguments); 311 } 312 } 313 314 315 316 /** 317 * Creates a new third-party task from the provided entry. 318 * 319 * @param entry The entry to use to create this third-party task. 320 * 321 * @throws TaskException If the provided entry cannot be parsed as a 322 * third-party task entry. 323 */ 324 public ThirdPartyTask(@NotNull final Entry entry) 325 throws TaskException 326 { 327 super(entry); 328 329 330 // Get the task class name. It must be present. 331 taskClassName = entry.getAttributeValue(ATTR_THIRD_PARTY_TASK_CLASS); 332 if (taskClassName == null) 333 { 334 throw new TaskException(ERR_THIRD_PARTY_TASK_NO_CLASS.get( 335 getTaskEntryDN())); 336 } 337 338 339 // Get the task arguments. It may be absent. 340 final String[] args = 341 entry.getAttributeValues(ATTR_THIRD_PARTY_TASK_ARGUMENT); 342 if ((args == null) || (args.length == 0)) 343 { 344 taskArguments = Collections.emptyList(); 345 } 346 else 347 { 348 taskArguments = Collections.unmodifiableList(Arrays.asList(args)); 349 } 350 } 351 352 353 354 /** 355 * Creates a new third-party task from the provided set of task properties. 356 * 357 * @param properties The set of task properties and their corresponding 358 * values to use for the task. It must not be 359 * {@code null}. 360 * 361 * @throws TaskException If the provided set of properties cannot be used to 362 * create a valid third-party task. 363 */ 364 public ThirdPartyTask( 365 @NotNull final Map<TaskProperty,List<Object>> properties) 366 throws TaskException 367 { 368 super(THIRD_PARTY_TASK_CLASS, properties); 369 370 String className = null; 371 String[] args = null; 372 for (final Map.Entry<TaskProperty,List<Object>> entry : 373 properties.entrySet()) 374 { 375 final TaskProperty p = entry.getKey(); 376 final String attrName = p.getAttributeName(); 377 final List<Object> values = entry.getValue(); 378 379 if (attrName.equalsIgnoreCase(ATTR_THIRD_PARTY_TASK_CLASS)) 380 { 381 className = parseString(p, values, null); 382 } 383 else if (attrName.equalsIgnoreCase(ATTR_THIRD_PARTY_TASK_ARGUMENT)) 384 { 385 args = parseStrings(p, values, null); 386 } 387 } 388 389 if (className == null) 390 { 391 throw new TaskException(ERR_THIRD_PARTY_TASK_NO_CLASS.get( 392 getTaskEntryDN())); 393 } 394 395 taskClassName = className; 396 397 if (args == null) 398 { 399 taskArguments = Collections.emptyList(); 400 } 401 else 402 { 403 taskArguments = Collections.unmodifiableList(Arrays.asList(args)); 404 } 405 } 406 407 408 409 /** 410 * {@inheritDoc} 411 */ 412 @Override() 413 @NotNull() 414 public String getTaskName() 415 { 416 return INFO_TASK_NAME_THIRD_PARTY_TASK.get(); 417 } 418 419 420 421 /** 422 * {@inheritDoc} 423 */ 424 @Override() 425 @NotNull() 426 public String getTaskDescription() 427 { 428 return INFO_TASK_DESCRIPTION_THIRD_PARTY_TASK.get(); 429 } 430 431 432 433 /** 434 * Retrieves the fully-qualified name of the Java class providing the logic 435 * for the third-party task. 436 * 437 * @return The fully-qualified name of the Java class providing the logic 438 * for the third-party task. 439 */ 440 @NotNull() 441 public String getThirdPartyTaskClassName() 442 { 443 return taskClassName; 444 } 445 446 447 448 /** 449 * Retrieves a list of the arguments to provide to the third-party task. 450 * 451 * @return A list of the arguments to provide to the third-party task, or 452 * an empty list if there are no arguments. 453 */ 454 @NotNull() 455 public List<String> getThirdPartyTaskArguments() 456 { 457 return taskArguments; 458 } 459 460 461 462 /** 463 * {@inheritDoc} 464 */ 465 @Override() 466 @NotNull() 467 protected List<String> getAdditionalObjectClasses() 468 { 469 return Collections.singletonList(OC_THIRD_PARTY_TASK); 470 } 471 472 473 474 /** 475 * {@inheritDoc} 476 */ 477 @Override() 478 @NotNull() 479 protected List<Attribute> getAdditionalAttributes() 480 { 481 final ArrayList<Attribute> attrList = new ArrayList<>(2); 482 attrList.add(new Attribute(ATTR_THIRD_PARTY_TASK_CLASS, taskClassName)); 483 484 if (! taskArguments.isEmpty()) 485 { 486 attrList.add(new Attribute(ATTR_THIRD_PARTY_TASK_ARGUMENT, 487 taskArguments)); 488 } 489 490 return attrList; 491 } 492 493 494 495 /** 496 * {@inheritDoc} 497 */ 498 @Override() 499 @NotNull() 500 public List<TaskProperty> getTaskSpecificProperties() 501 { 502 return Collections.unmodifiableList(Arrays.asList( 503 PROPERTY_TASK_CLASS, 504 PROPERTY_TASK_ARG)); 505 } 506 507 508 509 /** 510 * {@inheritDoc} 511 */ 512 @Override() 513 @NotNull() 514 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 515 { 516 final LinkedHashMap<TaskProperty,List<Object>> props = 517 new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); 518 519 props.put(PROPERTY_TASK_CLASS, 520 Collections.<Object>singletonList(taskClassName)); 521 522 props.put(PROPERTY_TASK_ARG, 523 Collections.<Object>unmodifiableList(taskArguments)); 524 525 props.putAll(super.getTaskPropertyValues()); 526 return Collections.unmodifiableMap(props); 527 } 528}