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