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 a task 047 * written as a Groovy script 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 Groovy class providing the logic for 062 * the scripted 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 GroovyScriptedTask 069 extends Task 070{ 071 /** 072 * The fully-qualified name of the Java class that is used for the core 073 * Groovy-scripted task. 074 */ 075 static final String GROOVY_SCRIPTED_TASK_CLASS = 076 "com.unboundid.directory.sdk.extensions.GroovyScriptedTask"; 077 078 079 080 /** 081 * The name of the attribute used to specify the fully-qualified name of the 082 * Groovy class providing the logic for the scripted task. 083 */ 084 private static final String ATTR_GROOVY_SCRIPTED_TASK_CLASS = 085 "ds-scripted-task-class"; 086 087 088 089 /** 090 * The name of the attribute used to provide arguments to the script. 091 */ 092 private static final String ATTR_GROOVY_SCRIPTED_TASK_ARGUMENT = 093 "ds-scripted-task-argument"; 094 095 096 097 /** 098 * The name of the object class used in Groovy-scripted task entries. 099 */ 100 private static final String OC_GROOVY_SCRIPTED_TASK = 101 "ds-groovy-scripted-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_GROOVY_SCRIPTED_TASK_CLASS, 110 INFO_DISPLAY_NAME_GROOVY_SCRIPTED_TASK_CLASS.get(), 111 INFO_DESCRIPTION_GROOVY_SCRIPTED_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_GROOVY_SCRIPTED_TASK_ARGUMENT, 121 INFO_DISPLAY_NAME_GROOVY_SCRIPTED_TASK_ARG.get(), 122 INFO_DESCRIPTION_GROOVY_SCRIPTED_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 = -1354970323227263273L; 131 132 133 134 // A list of the arguments for the task. 135 private final List<String> taskArguments; 136 137 // The name of the Groovy class providing the logic for the scripted task. 138 private final String taskClassName; 139 140 141 142 /** 143 * Creates a new uninitialized Groovy-scripted 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 GroovyScriptedTask() 149 { 150 taskArguments = null; 151 taskClassName = null; 152 } 153 154 155 156 /** 157 * Creates a new Groovy-scripted 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 Groovy class 163 * providing 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 GroovyScriptedTask(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 Groovy-scripted 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 Groovy 184 * class providing the logic for the task. It 185 * must 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 GroovyScriptedTask(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 Groovy-scripted 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 Groovy 227 * class providing the logic for the task. It 228 * must 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 GroovyScriptedTask(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, GROOVY_SCRIPTED_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 Groovy-scripted task from the provided entry. 298 * 299 * @param entry The entry to use to create this Groovy-scripted task. 300 * 301 * @throws TaskException If the provided entry cannot be parsed as a 302 * Groovy-scripted task entry. 303 */ 304 public GroovyScriptedTask(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_GROOVY_SCRIPTED_TASK_CLASS); 312 if (taskClassName == null) 313 { 314 throw new TaskException(ERR_GROOVY_SCRIPTED_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_GROOVY_SCRIPTED_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 Groovy-scripted task from the provided set of task 336 * properties. 337 * 338 * @param properties The set of task properties and their corresponding 339 * values to use for the task. It must not be 340 * {@code null}. 341 * 342 * @throws TaskException If the provided set of properties cannot be used to 343 * create a valid Groovy-scripted task. 344 */ 345 public GroovyScriptedTask(final Map<TaskProperty,List<Object>> properties) 346 throws TaskException 347 { 348 super(GROOVY_SCRIPTED_TASK_CLASS, properties); 349 350 String className = null; 351 String[] args = null; 352 for (final Map.Entry<TaskProperty,List<Object>> entry : 353 properties.entrySet()) 354 { 355 final TaskProperty p = entry.getKey(); 356 final String attrName = p.getAttributeName(); 357 final List<Object> values = entry.getValue(); 358 359 if (attrName.equalsIgnoreCase(ATTR_GROOVY_SCRIPTED_TASK_CLASS)) 360 { 361 className = parseString(p, values, null); 362 } 363 else if (attrName.equalsIgnoreCase(ATTR_GROOVY_SCRIPTED_TASK_ARGUMENT)) 364 { 365 args = parseStrings(p, values, null); 366 } 367 } 368 369 if (className == null) 370 { 371 throw new TaskException(ERR_GROOVY_SCRIPTED_TASK_NO_CLASS.get( 372 getTaskEntryDN())); 373 } 374 375 taskClassName = className; 376 377 if (args == null) 378 { 379 taskArguments = Collections.emptyList(); 380 } 381 else 382 { 383 taskArguments = Collections.unmodifiableList(Arrays.asList(args)); 384 } 385 } 386 387 388 389 /** 390 * {@inheritDoc} 391 */ 392 @Override() 393 public String getTaskName() 394 { 395 return INFO_TASK_NAME_GROOVY_SCRIPTED_TASK.get(); 396 } 397 398 399 400 /** 401 * {@inheritDoc} 402 */ 403 @Override() 404 public String getTaskDescription() 405 { 406 return INFO_TASK_DESCRIPTION_GROOVY_SCRIPTED_TASK.get(); 407 } 408 409 410 411 /** 412 * Retrieves the fully-qualified name of the Groovy class providing the logic 413 * for the scripted task. 414 * 415 * @return The fully-qualified name of the Groovy class providing the logic 416 * for the scripted task. 417 */ 418 public String getGroovyScriptedTaskClassName() 419 { 420 return taskClassName; 421 } 422 423 424 425 /** 426 * Retrieves a list of the arguments to provide to the Groovy-scripted task. 427 * 428 * @return A list of the arguments to provide to the Groovy-scripted task, or 429 * an empty list if there are no arguments. 430 */ 431 public List<String> getGroovyScriptedTaskArguments() 432 { 433 return taskArguments; 434 } 435 436 437 438 /** 439 * {@inheritDoc} 440 */ 441 @Override() 442 protected List<String> getAdditionalObjectClasses() 443 { 444 return Collections.singletonList(OC_GROOVY_SCRIPTED_TASK); 445 } 446 447 448 449 /** 450 * {@inheritDoc} 451 */ 452 @Override() 453 protected List<Attribute> getAdditionalAttributes() 454 { 455 final ArrayList<Attribute> attrList = new ArrayList<>(2); 456 attrList.add(new Attribute(ATTR_GROOVY_SCRIPTED_TASK_CLASS, taskClassName)); 457 458 if (! taskArguments.isEmpty()) 459 { 460 attrList.add(new Attribute(ATTR_GROOVY_SCRIPTED_TASK_ARGUMENT, 461 taskArguments)); 462 } 463 464 return attrList; 465 } 466 467 468 469 /** 470 * {@inheritDoc} 471 */ 472 @Override() 473 public List<TaskProperty> getTaskSpecificProperties() 474 { 475 return Collections.unmodifiableList(Arrays.asList( 476 PROPERTY_TASK_CLASS, 477 PROPERTY_TASK_ARG)); 478 } 479 480 481 482 /** 483 * {@inheritDoc} 484 */ 485 @Override() 486 public Map<TaskProperty,List<Object>> getTaskPropertyValues() 487 { 488 final LinkedHashMap<TaskProperty,List<Object>> props = 489 new LinkedHashMap<>(StaticUtils.computeMapCapacity(2)); 490 491 props.put(PROPERTY_TASK_CLASS, 492 Collections.<Object>singletonList(taskClassName)); 493 494 props.put(PROPERTY_TASK_ARG, 495 Collections.<Object>unmodifiableList(taskArguments)); 496 497 props.putAll(super.getTaskPropertyValues()); 498 return Collections.unmodifiableMap(props); 499 } 500}