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