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