- [Issue 274] Recurring Tasks
| | |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.60 |
| | | NAME 'ds-recurring-task-class-name' |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.515 |
| | | NAME 'ds-recurring-task-schedule' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | |
| | | ds-cfg-profile-sample-interval $ |
| | | ds-cfg-profile-action ) |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.38 |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.198 |
| | | NAME 'ds-recurring-task' |
| | | SUP top |
| | | STRUCTURAL |
| | | MUST ( ds-recurring-task-class-name $ |
| | | AUXILIARY |
| | | MUST ( ds-recurring-task-schedule $ |
| | | ds-recurring-task-id ) |
| | | MAY ( ds-task-notify-on-completion $ |
| | | ds-task-notify-on-error ) |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.39 |
| | | NAME 'ds-cfg-root-config' |
| | |
| | | SEVERE_ERR_RECURRINGTASK_MULTIPLE_ID_VALUES_103=The provided recurring task \ |
| | | entry contains multiple values for the %s attribute, which is used to specify \ |
| | | the recurring task ID, but only a single value is allowed |
| | | SEVERE_ERR_RECURRINGTASK_NO_CLASS_ATTRIBUTE_104=The provided recurring task \ |
| | | entry does not contain attribute %s which is needed to specify the \ |
| | | fully-qualified name of the class providing the task logic |
| | | SEVERE_ERR_RECURRINGTASK_MULTIPLE_CLASS_TYPES_105=The provided recurring task \ |
| | | entry contains multiple attributes with type %s, which is used to hold the \ |
| | | task class name, but only a single instance is allowed |
| | | SEVERE_ERR_RECURRINGTASK_NO_CLASS_VALUES_106=The provided recurring task \ |
| | | SEVERE_ERR_RECURRINGTASK_NO_SCHEDULE_ATTRIBUTE_104=The provided recurring task \ |
| | | entry does not contain attribute %s which is needed to specify recurring task \ |
| | | schedule |
| | | SEVERE_ERR_RECURRINGTASK_MULTIPLE_SCHEDULE_TYPES_105=The provided recurring \ |
| | | task entry contains multiple attributes with type %s, which is used to hold \ |
| | | recurring task schedule, but only a single instance is allowed |
| | | SEVERE_ERR_RECURRINGTASK_NO_SCHEDULE_VALUES_106=The provided recurring task \ |
| | | entry does not contain any values for the %s attribute, which is used to \ |
| | | specify the fully-qualified name of the class providing the task logic |
| | | SEVERE_ERR_RECURRINGTASK_MULTIPLE_CLASS_VALUES_107=The provided recurring \ |
| | | specify recurring task schedule |
| | | SEVERE_ERR_RECURRINGTASK_MULTIPLE_SCHEDULE_VALUES_107=The provided recurring \ |
| | | task entry contains multiple values for the %s attribute, which is used to \ |
| | | specify the task class name, but only a single value is allowed |
| | | specify recurring task schedule, but only a single value is allowed |
| | | SEVERE_ERR_RECURRINGTASK_CANNOT_LOAD_CLASS_108=An error occurred while \ |
| | | attempting to load class %s specified in attribute %s of the provided \ |
| | | recurring task entry: %s. Does this class exist in the Directory Server \ |
| | |
| | | MILD_ERR_NUM_SUBORDINATES_NOT_SUPPORTED_369=This backend does not provide \ |
| | | support for the numSubordinates operational attribute |
| | | NOTICE_BACKEND_OFFLINE_370=The backend %s is now taken offline |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_N_TOKENS_371=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid number \ |
| | | of tokens |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_MINUTE_TOKEN_372=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid minute \ |
| | | token |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_HOUR_TOKEN_373=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid hour \ |
| | | token |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_DAY_TOKEN_374=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid day of \ |
| | | the month token |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_MONTH_TOKEN_375=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid month of \ |
| | | the year token |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_WEEKDAY_TOKEN_376=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid day of the \ |
| | | week token |
| | | SEVERE_ERR_RECURRINGTASK_INVALID_TOKENS_COMBO_377=The provided recurring task \ |
| | | entry attribute %s holding the recurring task schedule has invalid tokens \ |
| | | combination yielding a nonexistent calendar date |
| | |
| | | INFO_IMPORT_ARG_RANDOM_SEED_105=Random Seed |
| | | SEVERE_ERR_TASK_LDAP_FAILED_TO_CONNECT_WRONG_PORT_106=Unable to connect to the \ |
| | | server at %s on port %s. Check this port is an administration port |
| | | INFO_TASK_STATE_RECURRING_107=Recurring |
| | |
| | | be canceled |
| | | INFO_TASKINFO_NO_CANCELABLE_TASKS_1452=There are currently no cancelable tasks |
| | | SEVERE_ERR_TASK_CLIENT_UNKNOWN_TASK_1453=There are no tasks defined with ID '%s' |
| | | SEVERE_ERR_TASK_CLIENT_UNCANCELABLE_TASK_1454=Task '%s' is has finished and \ |
| | | SEVERE_ERR_TASK_CLIENT_UNCANCELABLE_TASK_1454=Task '%s' has finished and \ |
| | | cannot be canceled |
| | | SEVERE_ERR_TASK_CLIENT_TASK_STATE_UNKNOWN_1455=State for task '%s' cannot be \ |
| | | determined |
| | |
| | | cannot be backuped is the directory %s: this directory is already a backup \ |
| | | directory for backend %s |
| | | |
| | | INFO_RECURRING_TASK_PLACEHOLDER_1651={schedulePattern} |
| | | INFO_DESCRIPTION_RECURRING_TASK_1652=Indicates the task is recurring and will \ |
| | | be scheduled according to the value argument expressed in crontab(5) \ |
| | | compatible time/date pattern |
| | | INFO_TASK_TOOL_RECURRING_TASK_SCHEDULED_1653=Recurring %s task %s scheduled \ |
| | | successfully |
| | |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.task; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Arrays; |
| | | import java.util.Date; |
| | | import java.util.GregorianCalendar; |
| | | import org.opends.messages.Message; |
| | | |
| | | |
| | |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | |
| | | import java.util.StringTokenizer; |
| | | import java.util.regex.Pattern; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | |
| | | import static org.opends.server.config.ConfigConstants.*; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.types.Attributes; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.RDN; |
| | | |
| | | import static org.opends.messages.BackendMessages.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | |
| | | |
| | | |
| | |
| | | // class. |
| | | private String taskClassName; |
| | | |
| | | // Task instance. |
| | | private Task task; |
| | | |
| | | // Task scheduler for this task. |
| | | private TaskScheduler taskScheduler; |
| | | |
| | | // Number of tokens in the task schedule tab. |
| | | private static final int TASKTAB_NUM_TOKENS = 5; |
| | | |
| | | /** |
| | | * Task tab fields. |
| | | */ |
| | | private static enum TaskTab {MINUTE, HOUR, DAY, MONTH, WEEKDAY}; |
| | | |
| | | // Exact match pattern. |
| | | private static final Pattern exactPattern = |
| | | Pattern.compile("\\d+"); |
| | | |
| | | // Range match pattern. |
| | | private static final Pattern rangePattern = |
| | | Pattern.compile("\\d+[-]\\d+"); |
| | | |
| | | // List match pattern. |
| | | private static final Pattern listPattern = |
| | | Pattern.compile("^(\\d+,)(.*)(\\d+)$"); |
| | | |
| | | // Boolean arrays holding task tab slots. |
| | | private boolean[] minutesArray; |
| | | private boolean[] hoursArray; |
| | | private boolean[] daysArray; |
| | | private boolean[] monthArray; |
| | | private boolean[] weekdayArray; |
| | | |
| | | /** |
| | | * Creates a new recurring task based on the information in the provided |
| | |
| | | public RecurringTask(TaskScheduler taskScheduler, Entry recurringTaskEntry) |
| | | throws DirectoryException |
| | | { |
| | | this.recurringTaskEntry = recurringTaskEntry; |
| | | this.taskScheduler = taskScheduler; |
| | | this.recurringTaskEntry = recurringTaskEntry; |
| | | this.recurringTaskEntryDN = recurringTaskEntry.getDN(); |
| | | |
| | | |
| | | // Get the recurring task ID from the entry. If there isn't one, then fail. |
| | | AttributeType attrType = DirectoryServer.getAttributeType( |
| | | ATTR_RECURRING_TASK_ID.toLowerCase()); |
| | |
| | | recurringTaskID = value.getStringValue(); |
| | | |
| | | |
| | | // FIXME -- Need to have some method of getting the scheduling information |
| | | // from the recurring task entry. |
| | | |
| | | |
| | | // Get the class name from the entry. If there isn't one, then fail. |
| | | // Get the schedule for this task. |
| | | attrType = DirectoryServer.getAttributeType( |
| | | ATTR_RECURRING_TASK_CLASS_NAME.toLowerCase()); |
| | | ATTR_RECURRING_TASK_SCHEDULE.toLowerCase()); |
| | | if (attrType == null) |
| | | { |
| | | attrType = DirectoryServer.getDefaultAttributeType( |
| | | ATTR_RECURRING_TASK_CLASS_NAME); |
| | | ATTR_RECURRING_TASK_SCHEDULE); |
| | | } |
| | | |
| | | attrList = recurringTaskEntry.getAttribute(attrType); |
| | | if ((attrList == null) || attrList.isEmpty()) |
| | | { |
| | | Message message = ERR_RECURRINGTASK_NO_CLASS_ATTRIBUTE.get( |
| | | ATTR_RECURRING_TASK_CLASS_NAME); |
| | | Message message = ERR_RECURRINGTASK_NO_SCHEDULE_ATTRIBUTE.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | if (attrList.size() > 0) |
| | | if (attrList.size() > 1) |
| | | { |
| | | Message message = ERR_RECURRINGTASK_MULTIPLE_CLASS_TYPES.get( |
| | | ATTR_RECURRING_TASK_CLASS_NAME); |
| | | Message message = ERR_RECURRINGTASK_MULTIPLE_SCHEDULE_TYPES.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | attr = attrList.get(0); |
| | | if (attr.isEmpty()) |
| | | { |
| | | Message message = |
| | | ERR_RECURRINGTASK_NO_CLASS_VALUES.get(ATTR_RECURRING_TASK_CLASS_NAME); |
| | | Message message = ERR_RECURRINGTASK_NO_SCHEDULE_VALUES.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | |
| | | value = iterator.next(); |
| | | if (iterator.hasNext()) |
| | | { |
| | | Message message = ERR_RECURRINGTASK_MULTIPLE_CLASS_VALUES.get( |
| | | ATTR_RECURRING_TASK_CLASS_NAME); |
| | | Message message = ERR_RECURRINGTASK_MULTIPLE_SCHEDULE_VALUES.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | String taskScheduleTab = value.getStringValue(); |
| | | parseTaskTab(taskScheduleTab); |
| | | |
| | | // Get the class name from the entry. If there isn't one, then fail. |
| | | attrType = DirectoryServer.getAttributeType( |
| | | ATTR_TASK_CLASS.toLowerCase()); |
| | | if (attrType == null) |
| | | { |
| | | attrType = DirectoryServer.getDefaultAttributeType(ATTR_TASK_CLASS); |
| | | } |
| | | |
| | | attrList = recurringTaskEntry.getAttribute(attrType); |
| | | if ((attrList == null) || attrList.isEmpty()) |
| | | { |
| | | Message message = ERR_TASKSCHED_NO_CLASS_ATTRIBUTE.get( |
| | | ATTR_TASK_CLASS); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | if (attrList.size() > 1) |
| | | { |
| | | Message message = ERR_TASKSCHED_MULTIPLE_CLASS_TYPES.get( |
| | | ATTR_TASK_CLASS); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | attr = attrList.get(0); |
| | | if (attr.isEmpty()) |
| | | { |
| | | Message message = |
| | | ERR_TASKSCHED_NO_CLASS_VALUES.get(ATTR_TASK_CLASS); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | | iterator = attr.iterator(); |
| | | value = iterator.next(); |
| | | if (iterator.hasNext()) |
| | | { |
| | | Message message = ERR_TASKSCHED_MULTIPLE_CLASS_VALUES.get( |
| | | ATTR_TASK_CLASS); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | Message message = ERR_RECURRINGTASK_CANNOT_LOAD_CLASS. |
| | | get(String.valueOf(taskClassName), ATTR_RECURRING_TASK_CLASS_NAME, |
| | | get(String.valueOf(taskClassName), ATTR_TASK_CLASS, |
| | | getExceptionMessage(e)); |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, |
| | | e); |
| | |
| | | |
| | | |
| | | // Make sure that the specified class can be instantiated as a task. |
| | | Task task; |
| | | try |
| | | { |
| | | task = (Task) taskClass.newInstance(); |
| | |
| | | /** |
| | | * Schedules the next iteration of this recurring task for processing. |
| | | * |
| | | * @return The task that has been scheduled for processing. |
| | | * @return The task that has been scheduled for processing. |
| | | * @throws DirectoryException to indicate an error. |
| | | */ |
| | | public Task scheduleNextIteration() |
| | | public Task scheduleNextIteration() throws DirectoryException |
| | | { |
| | | // NYI |
| | | return null; |
| | | Task nextTask = null; |
| | | Date nextTaskDate = null; |
| | | |
| | | try { |
| | | nextTaskDate = getNextIteration(); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_TOKENS_COMBO.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | |
| | | SimpleDateFormat dateFormat = new SimpleDateFormat( |
| | | DATE_FORMAT_COMPACT_LOCAL_TIME); |
| | | String nextTaskStartTime = dateFormat.format(nextTaskDate); |
| | | |
| | | try { |
| | | // Make a regular task iteration from this recurring task. |
| | | nextTask = task.getClass().newInstance(); |
| | | Entry nextTaskEntry = recurringTaskEntry.duplicate(false); |
| | | String nextTaskID = task.getTaskID() + " - " + |
| | | nextTaskDate.toString(); |
| | | String nextTaskIDName = NAME_PREFIX_TASK + "id"; |
| | | AttributeType taskIDAttrType = |
| | | DirectoryServer.getAttributeType(nextTaskIDName); |
| | | Attribute nextTaskIDAttr = Attributes.create( |
| | | taskIDAttrType, nextTaskID); |
| | | nextTaskEntry.replaceAttribute(nextTaskIDAttr); |
| | | RDN nextTaskRDN = RDN.decode(nextTaskIDName + "=" + nextTaskID); |
| | | DN nextTaskDN = new DN(nextTaskRDN, |
| | | taskScheduler.getTaskBackend().getScheduledTasksParentDN()); |
| | | nextTaskEntry.setDN(nextTaskDN); |
| | | |
| | | String nextTaskStartTimeName = NAME_PREFIX_TASK + |
| | | "scheduled-start-time"; |
| | | AttributeType taskStartTimeAttrType = |
| | | DirectoryServer.getAttributeType(nextTaskStartTimeName); |
| | | Attribute nextTaskStartTimeAttr = Attributes.create( |
| | | taskStartTimeAttrType, nextTaskStartTime); |
| | | nextTaskEntry.replaceAttribute(nextTaskStartTimeAttr); |
| | | |
| | | nextTask.initializeTaskInternal(taskScheduler, nextTaskEntry); |
| | | nextTask.initializeTask(); |
| | | } catch (Exception e) { |
| | | // Should not happen, debug log it otherwise. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | } |
| | | |
| | | return nextTask; |
| | | } |
| | | |
| | | /** |
| | | * Parse and validate recurring task schedule. |
| | | * @param taskSchedule recurring task schedule tab in crontab(5) format. |
| | | * @throws DirectoryException to indicate an error. |
| | | */ |
| | | private void parseTaskTab(String taskSchedule) throws DirectoryException |
| | | { |
| | | StringTokenizer st = new StringTokenizer(taskSchedule); |
| | | |
| | | if (st.countTokens() != TASKTAB_NUM_TOKENS) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_N_TOKENS.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | |
| | | for (TaskTab taskTabToken : TaskTab.values()) { |
| | | String token = st.nextToken(); |
| | | switch (taskTabToken) { |
| | | case MINUTE: |
| | | try { |
| | | minutesArray = parseTaskTabField(token, 0, 59); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_MINUTE_TOKEN.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | break; |
| | | case HOUR: |
| | | try { |
| | | hoursArray = parseTaskTabField(token, 0, 23); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_HOUR_TOKEN.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | break; |
| | | case DAY: |
| | | try { |
| | | daysArray = parseTaskTabField(token, 1, 31); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_DAY_TOKEN.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | break; |
| | | case MONTH: |
| | | try { |
| | | monthArray = parseTaskTabField(token, 1, 12); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_MONTH_TOKEN.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | break; |
| | | case WEEKDAY: |
| | | try { |
| | | weekdayArray = parseTaskTabField(token, 0, 6); |
| | | } catch (IllegalArgumentException e) { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_RECURRINGTASK_INVALID_WEEKDAY_TOKEN.get( |
| | | ATTR_RECURRING_TASK_SCHEDULE)); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Parse and validate recurring task schedule field. |
| | | * @param tabField recurring task schedule field in crontab(5) format. |
| | | * @param minValue minimum value allowed for this field. |
| | | * @param maxValue maximum value allowed for this field. |
| | | * @return boolean schedule slots range set according to |
| | | * the schedule field. |
| | | * @throws IllegalArgumentException if tab field is invalid. |
| | | */ |
| | | private boolean[] parseTaskTabField(String tabField, |
| | | int minValue, int maxValue) throws IllegalArgumentException |
| | | { |
| | | boolean[] valueList = new boolean[maxValue + 1]; |
| | | Arrays.fill(valueList, false); |
| | | |
| | | // Blanket. |
| | | if (tabField.equals("*")) { |
| | | for (int i = minValue; i <= maxValue; i++) { |
| | | valueList[i] = true; |
| | | } |
| | | return valueList; |
| | | } |
| | | |
| | | // Exact. |
| | | if (exactPattern.matcher(tabField).matches()) { |
| | | int value = Integer.parseInt(tabField); |
| | | if ((value >= minValue) && (value <= maxValue)) { |
| | | valueList[value] = true; |
| | | return valueList; |
| | | } |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | |
| | | // Range. |
| | | if (rangePattern.matcher(tabField).matches()) { |
| | | StringTokenizer st = new StringTokenizer(tabField, "-"); |
| | | int startValue = Integer.parseInt(st.nextToken()); |
| | | int endValue = Integer.parseInt(st.nextToken()); |
| | | if ((startValue < endValue) && |
| | | ((startValue >= minValue) && (endValue <= maxValue))) |
| | | { |
| | | for (int i = startValue; i <= endValue; i++) { |
| | | valueList[i] = true; |
| | | } |
| | | return valueList; |
| | | } |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | |
| | | // List. |
| | | if (listPattern.matcher(tabField).matches()) { |
| | | StringTokenizer st = new StringTokenizer(tabField, ","); |
| | | while (st.hasMoreTokens()) { |
| | | int value = Integer.parseInt(st.nextToken()); |
| | | if ((value >= minValue) && (value <= maxValue)) { |
| | | valueList[value] = true; |
| | | } else { |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | } |
| | | return valueList; |
| | | } |
| | | |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | |
| | | /** |
| | | * Get next reccuring slot from the range. |
| | | * @param timesList the range. |
| | | * @param fromNow the current slot. |
| | | * @return next recurring slot in the range. |
| | | */ |
| | | private int getNextTimeSlice(boolean[] timesList, int fromNow) |
| | | { |
| | | for (int i = fromNow; i < timesList.length; i++) { |
| | | if (timesList[i]) { |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | /** |
| | | * Get next task iteration date according to recurring schedule. |
| | | * @return next task iteration date. |
| | | * @throws IllegalArgumentException if recurring schedule is invalid. |
| | | */ |
| | | private Date getNextIteration() throws IllegalArgumentException |
| | | { |
| | | int minute, hour, day, month, weekday; |
| | | GregorianCalendar calendar = new GregorianCalendar(); |
| | | calendar.setFirstDayOfWeek(GregorianCalendar.SUNDAY); |
| | | calendar.add(GregorianCalendar.MINUTE, 1); |
| | | calendar.set(GregorianCalendar.SECOND, 0); |
| | | calendar.setLenient(false); |
| | | |
| | | // Weekday |
| | | for (;;) { |
| | | // Month |
| | | for (;;) { |
| | | // Day |
| | | for (;;) { |
| | | // Hour |
| | | for (;;) { |
| | | // Minute |
| | | for (;;) { |
| | | minute = getNextTimeSlice(minutesArray, |
| | | calendar.get(GregorianCalendar.MINUTE)); |
| | | if (minute == -1) { |
| | | calendar.set(GregorianCalendar.MINUTE, 0); |
| | | calendar.add(GregorianCalendar.HOUR_OF_DAY, 1); |
| | | } else { |
| | | calendar.set(GregorianCalendar.MINUTE, minute); |
| | | break; |
| | | } |
| | | } |
| | | hour = getNextTimeSlice(hoursArray, |
| | | calendar.get(GregorianCalendar.HOUR_OF_DAY)); |
| | | if (hour == -1) { |
| | | calendar.set(GregorianCalendar.HOUR_OF_DAY, 0); |
| | | calendar.add(GregorianCalendar.DAY_OF_MONTH, 1); |
| | | } else { |
| | | calendar.set(GregorianCalendar.HOUR_OF_DAY, hour); |
| | | break; |
| | | } |
| | | } |
| | | day = getNextTimeSlice(daysArray, |
| | | calendar.get(GregorianCalendar.DAY_OF_MONTH)); |
| | | if (day == -1) { |
| | | calendar.set(GregorianCalendar.DAY_OF_MONTH, 1); |
| | | calendar.add(GregorianCalendar.MONTH, 1); |
| | | } else { |
| | | calendar.set(GregorianCalendar.DAY_OF_MONTH, day); |
| | | break; |
| | | } |
| | | } |
| | | month = getNextTimeSlice(monthArray, |
| | | (calendar.get(GregorianCalendar.MONTH) + 1)); |
| | | if (month == -1) { |
| | | calendar.set(GregorianCalendar.MONTH, 0); |
| | | calendar.add(GregorianCalendar.YEAR, 1); |
| | | } else { |
| | | calendar.set(GregorianCalendar.MONTH, (month - 1)); |
| | | break; |
| | | } |
| | | } |
| | | weekday = getNextTimeSlice(weekdayArray, |
| | | (calendar.get(GregorianCalendar.DAY_OF_WEEK) - 1)); |
| | | if ((weekday == -1) || |
| | | (weekday != (calendar.get( |
| | | GregorianCalendar.DAY_OF_WEEK) - 1))) |
| | | { |
| | | calendar.add(GregorianCalendar.DAY_OF_MONTH, 1); |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return calendar.getTime(); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether or not this task is an iteration of |
| | | * some recurring task. |
| | | * |
| | | * @return boolean where true indicates that this task is |
| | | * recurring, false otherwise. |
| | | */ |
| | | public boolean isRecurring() |
| | | { |
| | | return (recurringTaskID != null); |
| | | } |
| | | |
| | | /** |
| | | * Indicates whether or not this task has been cancelled. |
| | | * |
| | | * @return boolean where true indicates that this task was |
| | |
| | | TaskState state = t.getTaskState(); |
| | | if (TaskState.isPending(state)) |
| | | { |
| | | taskScheduler.removePendingTask(t.getTaskID()); |
| | | if (t.isRecurring()) { |
| | | taskScheduler.removeRecurringTaskIteration(t.getTaskID()); |
| | | } else { |
| | | taskScheduler.removePendingTask(t.getTaskID()); |
| | | } |
| | | } |
| | | else if (TaskState.isDone(t.getTaskState())) |
| | | { |
| | |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); |
| | | } |
| | | |
| | | |
| | | // Try to remove the recurring task. This will fail if there are any |
| | | // associated iterations pending or running. |
| | | taskScheduler.removeRecurringTask(rt.getRecurringTaskID()); |
| | | } |
| | | else |
| | |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); |
| | | } |
| | | |
| | | |
| | | // Look at the state of the task. We will allow anything to be altered |
| | | // for a pending task. For a running task, we will only allow the state |
| | | // to be altered in order to cancel it. We will not allow any |
| | | // modifications for completed tasks. |
| | | TaskState state = t.getTaskState(); |
| | | if (TaskState.isPending(state)) |
| | | if (TaskState.isPending(state) && !t.isRecurring()) |
| | | { |
| | | Task newTask = taskScheduler.entryToScheduledTask(newEntry, |
| | | modifyOperation); |
| | |
| | | // This will only be allowed using the replace modification type on |
| | | // the ds-task-state attribute if the value starts with "cancel" or |
| | | // "stop". In that case, we'll cancel the task. |
| | | boolean acceptable = true; |
| | | for (Modification m : modifyOperation.getModifications()) |
| | | { |
| | | if (m.isInternal()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (m.getModificationType() != ModificationType.REPLACE) |
| | | { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | Attribute a = m.getAttribute(); |
| | | AttributeType at = a.getAttributeType(); |
| | | if (! at.hasName(ATTR_TASK_STATE)) |
| | | { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | Iterator<AttributeValue> iterator = a.iterator(); |
| | | if (! iterator.hasNext()) |
| | | { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | AttributeValue v = iterator.next(); |
| | | String valueString = toLowerCase(v.getStringValue()); |
| | | if (! (valueString.startsWith("cancel") || |
| | | valueString.startsWith("stop"))) |
| | | { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | if (iterator.hasNext()) |
| | | { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | } |
| | | boolean acceptable = isReplaceEntryAcceptable(modifyOperation); |
| | | |
| | | if (acceptable) |
| | | { |
| | |
| | | message); |
| | | } |
| | | } |
| | | else if (TaskState.isPending(state) && t.isRecurring()) |
| | | { |
| | | // Pending recurring task iterations can only be canceled. |
| | | boolean acceptable = isReplaceEntryAcceptable(modifyOperation); |
| | | |
| | | if (acceptable) |
| | | { |
| | | Task newTask = taskScheduler.entryToScheduledTask(newEntry, |
| | | modifyOperation); |
| | | if (newTask.getTaskState() == |
| | | TaskState.CANCELED_BEFORE_STARTING) |
| | | { |
| | | taskScheduler.removePendingTask(t.getTaskID()); |
| | | taskScheduler.scheduleTask(newTask, true); |
| | | } |
| | | else if (newTask.getTaskState() == |
| | | TaskState.STOPPED_BY_ADMINISTRATOR) |
| | | { |
| | | Message message = INFO_TASKBE_RUNNING_TASK_CANCELLED.get(); |
| | | t.interruptTask(TaskState.STOPPED_BY_ADMINISTRATOR, message); |
| | | } |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | Message message = |
| | | ERR_TASKBE_MODIFY_RECURRING.get(String.valueOf(entryDN)); |
| | | throw new DirectoryException( |
| | | ResultCode.UNWILLING_TO_PERFORM, message); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Message message = |
| | |
| | | |
| | | |
| | | /** |
| | | * Helper to determine if requested modifications are acceptable. |
| | | * @param modifyOperation associated with requested modifications. |
| | | * @return <CODE>true</CODE> if requested modifications are |
| | | * acceptable, <CODE>false</CODE> otherwise. |
| | | */ |
| | | private boolean isReplaceEntryAcceptable(ModifyOperation modifyOperation) |
| | | { |
| | | boolean acceptable = true; |
| | | |
| | | for (Modification m : modifyOperation.getModifications()) { |
| | | if (m.isInternal()) { |
| | | continue; |
| | | } |
| | | |
| | | if (m.getModificationType() != ModificationType.REPLACE) { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | Attribute a = m.getAttribute(); |
| | | AttributeType at = a.getAttributeType(); |
| | | if (!at.hasName(ATTR_TASK_STATE)) { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | Iterator<AttributeValue> iterator = a.iterator(); |
| | | if (!iterator.hasNext()) { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | AttributeValue v = iterator.next(); |
| | | String valueString = toLowerCase(v.getStringValue()); |
| | | if (!(valueString.startsWith("cancel") || |
| | | valueString.startsWith("stop"))) { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | |
| | | if (iterator.hasNext()) { |
| | | acceptable = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return acceptable; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedHashMap; |
| | |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Attributes; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.DirectoryException; |
| | |
| | | DirectoryServer.registerAlertGenerator(this); |
| | | |
| | | initializeTasksFromBackingFile(); |
| | | |
| | | for (RecurringTask recurringTask : recurringTasks.values()) { |
| | | Task task = null; |
| | | try { |
| | | task = recurringTask.scheduleNextIteration(); |
| | | } catch (DirectoryException de) { |
| | | logError(de.getMessageObject()); |
| | | } |
| | | if (task != null) { |
| | | try { |
| | | scheduleTask(task, false); |
| | | } catch (DirectoryException de) { |
| | | // This task might have been already scheduled from before |
| | | // and thus got initialized from backing file, otherwise |
| | | // log error and continue. |
| | | if (de.getResultCode() != ResultCode.ENTRY_ALREADY_EXISTS) { |
| | | logError(de.getMessageObject()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | throw new DirectoryException(ResultCode.ENTRY_ALREADY_EXISTS, message); |
| | | } |
| | | |
| | | recurringTasks.put(id, recurringTask); |
| | | Attribute attr = Attributes.create(ATTR_TASK_STATE, |
| | | TaskState.RECURRING.toString()); |
| | | ArrayList<Attribute> attrList = new ArrayList<Attribute>(1); |
| | | attrList.add(attr); |
| | | Entry recurringTaskEntry = recurringTask.getRecurringTaskEntry(); |
| | | recurringTaskEntry.putAttribute(attr.getAttributeType(), attrList); |
| | | |
| | | if (scheduleIteration) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | recurringTasks.put(id, recurringTask); |
| | | writeState(); |
| | | } |
| | | finally |
| | |
| | | |
| | | try |
| | | { |
| | | RecurringTask recurringTask = recurringTasks.remove(recurringTaskID); |
| | | writeState(); |
| | | |
| | | for (Task t : tasks.values()) |
| | | { |
| | | if ((t.getRecurringTaskID() != null) && |
| | | (t.getRecurringTaskID().equals(recurringTaskID)) && |
| | | (! TaskState.isDone(t.getTaskState()))) |
| | | (!TaskState.isDone(t.getTaskState()))) |
| | | { |
| | | Message message = ERR_TASKSCHED_REMOVE_RECURRING_EXISTING_ITERATION. |
| | | get(String.valueOf(recurringTaskID), |
| | | String.valueOf(t.getTaskID())); |
| | | throw new DirectoryException( |
| | | ResultCode.UNWILLING_TO_PERFORM, message); |
| | | cancelTask(t.getTaskID()); |
| | | } |
| | | } |
| | | |
| | | |
| | | RecurringTask recurringTask = recurringTasks.remove(recurringTaskID); |
| | | writeState(); |
| | | |
| | | return recurringTask; |
| | | } |
| | | finally |
| | |
| | | } |
| | | else if (TaskState.isDone(state)) |
| | | { |
| | | completedTasks.add(task); |
| | | if ((state == TaskState.CANCELED_BEFORE_STARTING) && |
| | | task.isRecurring()) |
| | | { |
| | | pendingTasks.add(task); |
| | | } |
| | | else |
| | | { |
| | | completedTasks.add(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * Removes the specified pending iteration of recurring task. It will |
| | | * be removed from the task set but still be kept in the pending set. |
| | | * |
| | | * @param taskID The task ID of the pending iteration to remove. |
| | | * |
| | | * @return The task that was removed. |
| | | * |
| | | * @throws DirectoryException If the requested task is not in the |
| | | * pending queue. |
| | | */ |
| | | public Task removeRecurringTaskIteration(String taskID) |
| | | throws DirectoryException |
| | | { |
| | | schedulerLock.lock(); |
| | | |
| | | try |
| | | { |
| | | Task t = tasks.get(taskID); |
| | | if (t == null) |
| | | { |
| | | Message message = ERR_TASKSCHED_REMOVE_PENDING_NO_SUCH_TASK.get( |
| | | String.valueOf(taskID)); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message); |
| | | } |
| | | |
| | | if (TaskState.isPending(t.getTaskState())) |
| | | { |
| | | tasks.remove(taskID); |
| | | writeState(); |
| | | return t; |
| | | } |
| | | else |
| | | { |
| | | Message message = ERR_TASKSCHED_REMOVE_PENDING_NOT_PENDING.get( |
| | | String.valueOf(taskID)); |
| | | throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | schedulerLock.unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Removes the specified completed task. |
| | | * |
| | | * @param taskID The task ID of the completed task to remove. |
| | |
| | | } |
| | | else |
| | | { |
| | | Task newIteration = recurringTask.scheduleNextIteration(); |
| | | Task newIteration = null; |
| | | try { |
| | | newIteration = recurringTask.scheduleNextIteration(); |
| | | } catch (DirectoryException de) { |
| | | logError(de.getMessageObject()); |
| | | } |
| | | if (newIteration != null) |
| | | { |
| | | // FIXME -- What to do if new iteration is null? |
| | |
| | | * Operates in a loop, launching tasks at the appropriate time and performing |
| | | * any necessary periodic cleanup. |
| | | */ |
| | | @Override |
| | | public void run() |
| | | { |
| | | isRunning = true; |
| | |
| | | long waitTime = t.getScheduledStartTime() - TimeThread.getTime(); |
| | | sleepTime = Math.min(sleepTime, waitTime); |
| | | } |
| | | // Recurring task iteration has to spawn the next one |
| | | // even if the current iteration has been canceled. |
| | | else if ((state == TaskState.CANCELED_BEFORE_STARTING) && |
| | | t.isRecurring()) |
| | | { |
| | | if (t.getScheduledStartTime() > TimeThread.getTime()) { |
| | | // If we're waiting for the start time to arrive, |
| | | // then see if that will come before the next |
| | | // sleep time is up. |
| | | long waitTime = |
| | | t.getScheduledStartTime() - TimeThread.getTime(); |
| | | sleepTime = Math.min(sleepTime, waitTime); |
| | | } else { |
| | | TaskThread taskThread; |
| | | if (idleThreads.isEmpty()) { |
| | | taskThread = new TaskThread(this, nextThreadID++); |
| | | taskThread.start(); |
| | | } else { |
| | | taskThread = idleThreads.removeFirst(); |
| | | } |
| | | runningTasks.add(t); |
| | | activeThreads.put(t.getTaskID(), taskThread); |
| | | taskThread.setTask(t); |
| | | } |
| | | } |
| | | |
| | | if (state != t.getTaskState()) |
| | | { |
| | |
| | | { |
| | | // If the task has finished we don't want to restart it |
| | | TaskState state = task.getTaskState(); |
| | | if (state != null && TaskState.isDone(state)) |
| | | |
| | | // Reset task state if recurring. |
| | | if (state == TaskState.RECURRING) { |
| | | state = null; |
| | | } |
| | | |
| | | if ((state != null) && TaskState.isDone(state)) |
| | | { |
| | | return state; |
| | | } |
| | |
| | | String.valueOf(taskBackend.getTaskRootDN())); |
| | | logError(message); |
| | | } |
| | | else if (parentDN.equals(taskBackend.getRecurringTasksParentDN())) |
| | | { |
| | | try |
| | | { |
| | | RecurringTask recurringTask = entryToRecurringTask(entry); |
| | | addRecurringTask(recurringTask, false); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | |
| | | Message message = |
| | | ERR_TASKSCHED_CANNOT_SCHEDULE_RECURRING_TASK_FROM_ENTRY. |
| | | get(String.valueOf(entryDN), de.getMessageObject()); |
| | | logError(message); |
| | | } |
| | | } |
| | | else if (parentDN.equals(taskBackend.getScheduledTasksParentDN())) |
| | | { |
| | | try |
| | |
| | | logError(message); |
| | | } |
| | | } |
| | | else if (parentDN.equals(taskBackend.getRecurringTasksParentDN())) |
| | | { |
| | | try |
| | | { |
| | | RecurringTask recurringTask = entryToRecurringTask(entry); |
| | | addRecurringTask(recurringTask, false); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | |
| | | Message message = |
| | | ERR_TASKSCHED_CANNOT_SCHEDULE_RECURRING_TASK_FROM_ENTRY. |
| | | get(String.valueOf(entryDN), de.getMessageObject()); |
| | | logError(message); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Message message = ERR_TASKSCHED_INVALID_TASK_ENTRY_DN.get( |
| | |
| | | |
| | | |
| | | /** |
| | | * The task state that indicates that the task is recurring. |
| | | */ |
| | | RECURRING(INFO_TASK_STATE_RECURRING.get()), |
| | | |
| | | |
| | | |
| | | /** |
| | | * The task state that indicates that the task has completed without any |
| | | * errors. |
| | | */ |
| | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether a task with the specified state is recurring. |
| | | * |
| | | * @param taskState The task state for which to make the determination. |
| | | * |
| | | * @return <CODE>true</CODE> if the task state indicates that the task |
| | | * is recurring, or <CODE>false</CODE> otherwise. |
| | | */ |
| | | public static boolean isRecurring(TaskState taskState) |
| | | { |
| | | switch (taskState) |
| | | { |
| | | case RECURRING: |
| | | return true; |
| | | default: |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether a task with the specified state has completed all the |
| | | * processing that it will do, regardless of whether it completed its |
| | | * intended goal. |
| | |
| | | { |
| | | return RUNNING; |
| | | } |
| | | else if (lowerString.equals("recurring")) |
| | | { |
| | | return RECURRING; |
| | | } |
| | | else if (lowerString.equals("completed_successfully")) |
| | | { |
| | | return COMPLETED_SUCCESSFULLY; |
| | |
| | | |
| | | try |
| | | { |
| | | TaskState returnState = getAssociatedTask().execute(); |
| | | getAssociatedTask().setTaskState(returnState); |
| | | if (!TaskState.isDone(getAssociatedTask().getTaskState())) |
| | | { |
| | | TaskState returnState = getAssociatedTask().execute(); |
| | | getAssociatedTask().setTaskState(returnState); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | |
| | | |
| | | /** |
| | | * The name of the configuration attribute that holds the name of the class |
| | | * used to provide the implementation logic for a recurring task. |
| | | * The name of the configuration attribute that holds the |
| | | * schedule for a recurring task. |
| | | */ |
| | | public static final String ATTR_RECURRING_TASK_CLASS_NAME = |
| | | NAME_PREFIX_RECURRING_TASK + "class-name"; |
| | | public static final String ATTR_RECURRING_TASK_SCHEDULE = |
| | | NAME_PREFIX_RECURRING_TASK + "schedule"; |
| | | |
| | | |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message getDisplayName() { |
| | | return INFO_TASK_BACKUP_NAME.get(); |
| | | } |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Message getAttributeDisplayName(String attrName) { |
| | | return argDisplayMap.get(attrName); |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | // Use task id for backup id in case of recurring task. |
| | | if (super.isRecurring()) { |
| | | backupID = super.getTaskID(); |
| | | } |
| | | |
| | | |
| | | // If no backup ID was provided, then create one with the current timestamp. |
| | | if (backupID == null) |
| | | { |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void interruptTask(TaskState interruptState, Message interruptReason) |
| | | { |
| | | if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) && |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isInterruptable() { |
| | | return true; |
| | | } |
| | |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getTaskId() { |
| | | if (backupIDString != null) { |
| | | return backupIDString.getValue(); |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getTaskId() { |
| | | // NYI. |
| | | return null; |
| | | } |
| | | } |
| | | |
| | |
| | | importConfig.close(); |
| | | return retCode; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getTaskId() { |
| | | // NYI. |
| | | return null; |
| | | } |
| | | } |
| | | |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | import org.opends.server.backends.task.TaskState; |
| | | |
| | | /** |
| | | * Tool for getting information and managing tasks in the Directory Server. |
| | |
| | | new TaskDrilldownMenu(taskId), |
| | | taskEntry.getType(), taskEntry.getState()); |
| | | index++; |
| | | if (taskEntry.isCancelable() && !taskEntry.isDone()) { |
| | | if (taskEntry.isCancelable()) { |
| | | cancelableIndices.add(index); |
| | | } |
| | | } |
| | | } else { |
| | | // println(); |
| | | getOutputStream().println(INFO_TASKINFO_NO_TASKS.get()); |
| | | getOutputStream().println(); |
| | | } |
| | |
| | | public MenuResult<TaskEntry> invoke(ManageTasks app) |
| | | throws CLIException |
| | | { |
| | | Message m = null; |
| | | TaskEntry taskEntry = null; |
| | | try { |
| | | taskEntry = app.getTaskClient().getTaskEntry(taskId); |
| | |
| | | table.appendCell(INFO_TASKINFO_FIELD_STATUS.get()); |
| | | table.appendCell(taskEntry.getState()); |
| | | |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_SCHEDULED_START.get()); |
| | | Message m = taskEntry.getScheduledStartTime(); |
| | | if (m == null || m.equals(Message.EMPTY)) { |
| | | table.appendCell(INFO_TASKINFO_IMMEDIATE_EXECUTION.get()); |
| | | } else { |
| | | if (TaskState.isRecurring(taskEntry.getTaskState())) { |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_SCHEDULED_START.get()); |
| | | m = taskEntry.getScheduleTab(); |
| | | table.appendCell(m); |
| | | } else { |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_SCHEDULED_START.get()); |
| | | m = taskEntry.getScheduledStartTime(); |
| | | if (m == null || m.equals(Message.EMPTY)) { |
| | | table.appendCell(INFO_TASKINFO_IMMEDIATE_EXECUTION.get()); |
| | | } else { |
| | | table.appendCell(m); |
| | | } |
| | | |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_ACTUAL_START.get()); |
| | | table.appendCell(taskEntry.getActualStartTime()); |
| | | |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_COMPLETION_TIME.get()); |
| | | table.appendCell(taskEntry.getCompletionTime()); |
| | | } |
| | | |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_ACTUAL_START.get()); |
| | | table.appendCell(taskEntry.getActualStartTime()); |
| | | |
| | | table.startRow(); |
| | | table.appendCell(INFO_TASKINFO_FIELD_COMPLETION_TIME.get()); |
| | | table.appendCell(taskEntry.getCompletionTime()); |
| | | |
| | | writeMultiValueCells( |
| | | table, |
| | | INFO_TASKINFO_FIELD_DEPENDENCY.get(), |
| | |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getTaskId() { |
| | | if (backupIDString != null) { |
| | | return backupIDString.getValue(); |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | public static final Character OPTION_SHORT_START_DATETIME = 't'; |
| | | |
| | | /** |
| | | * Recurring task option long form. |
| | | */ |
| | | public static final String OPTION_LONG_RECURRING_TASK = "recurringTask"; |
| | | |
| | | /** |
| | | * Recurring task option short form. |
| | | */ |
| | | public static final Character OPTION_SHORT_RECURRING_TASK = null; |
| | | |
| | | /** |
| | | * The value for the long option propertiesFilePAth . |
| | | */ |
| | | public static final String OPTION_LONG_PROP_FILE_PATH = "propertiesFilePath"; |
| | |
| | | import java.util.Date; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import org.opends.server.protocols.ldap.DeleteRequestProtocolOp; |
| | | import org.opends.server.protocols.ldap.DeleteResponseProtocolOp; |
| | | |
| | | /** |
| | | * Helper class for interacting with the task backend on behalf of utilities |
| | |
| | | public synchronized TaskEntry schedule(TaskScheduleInformation information) |
| | | throws LDAPException, IOException, ASN1Exception, TaskClientException |
| | | { |
| | | String taskID = null; |
| | | ASN1OctetString entryDN = null; |
| | | boolean scheduleRecurring = false; |
| | | |
| | | LDAPReader reader = connection.getLDAPReader(); |
| | | LDAPWriter writer = connection.getLDAPWriter(); |
| | | |
| | | // Use a formatted time/date for the ID so that is remotely useful |
| | | SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmssMM"); |
| | | String taskID = df.format(new Date()); |
| | | if (information.getRecurringDateTime() != null) { |
| | | scheduleRecurring = true; |
| | | } |
| | | |
| | | ASN1OctetString entryDN = |
| | | new ASN1OctetString(ATTR_TASK_ID + "=" + taskID + "," + |
| | | SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT); |
| | | if (scheduleRecurring) { |
| | | taskID = information.getTaskId(); |
| | | if ((taskID == null) || taskID.length() == 0) { |
| | | taskID = information.getTaskClass().getSimpleName() + |
| | | "-" + UUID.randomUUID().toString(); |
| | | } |
| | | entryDN = new ASN1OctetString(ATTR_RECURRING_TASK_ID + "=" + |
| | | taskID + "," + RECURRING_TASK_BASE_RDN + "," + DN_TASK_ROOT); |
| | | } else { |
| | | // Use a formatted time/date for the ID so that is remotely useful |
| | | SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmssMM"); |
| | | taskID = df.format(new Date()); |
| | | |
| | | entryDN = new ASN1OctetString(ATTR_TASK_ID + "=" + taskID + "," + |
| | | SCHEDULED_TASK_BASE_RDN + "," + DN_TASK_ROOT); |
| | | } |
| | | |
| | | ArrayList<LDAPControl> controls = new ArrayList<LDAPControl>(); |
| | | |
| | |
| | | ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>(3); |
| | | ocValues.add(new ASN1OctetString("top")); |
| | | ocValues.add(new ASN1OctetString(ConfigConstants.OC_TASK)); |
| | | |
| | | if (scheduleRecurring) { |
| | | ocValues.add(new ASN1OctetString(ConfigConstants.OC_RECURRING_TASK)); |
| | | } |
| | | |
| | | ocValues.add(new ASN1OctetString(information.getTaskObjectclass())); |
| | | attributes.add(new LDAPAttribute(ATTR_OBJECTCLASS, ocValues)); |
| | | |
| | | ArrayList<ASN1OctetString> taskIDValues = new ArrayList<ASN1OctetString>(1); |
| | | taskIDValues.add(new ASN1OctetString(taskID)); |
| | | |
| | | if (scheduleRecurring) { |
| | | attributes.add(new LDAPAttribute(ATTR_RECURRING_TASK_ID, taskIDValues)); |
| | | } |
| | | attributes.add(new LDAPAttribute(ATTR_TASK_ID, taskIDValues)); |
| | | |
| | | ArrayList<ASN1OctetString> classValues = new ArrayList<ASN1OctetString>(1); |
| | |
| | | startDateValues)); |
| | | } |
| | | |
| | | if (scheduleRecurring) { |
| | | ArrayList<ASN1OctetString> recurringPatternValues = |
| | | new ArrayList<ASN1OctetString>(1); |
| | | recurringPatternValues.add(new ASN1OctetString( |
| | | information.getRecurringDateTime())); |
| | | attributes.add(new LDAPAttribute(ATTR_RECURRING_TASK_SCHEDULE, |
| | | recurringPatternValues)); |
| | | } |
| | | |
| | | // add dependency IDs |
| | | List<String> dependencyIds = information.getDependencyIds(); |
| | | if (dependencyIds != null && dependencyIds.size() > 0) { |
| | |
| | | * Changes that the state of the task in the backend to a canceled state. |
| | | * |
| | | * @param id if the task to cancel |
| | | * @return Entry of the task before the modification |
| | | * @throws IOException if there is a stream communication problem |
| | | * @throws LDAPException if there is a problem getting information |
| | | * out to the directory |
| | | * @throws ASN1Exception if there is a problem with the encoding |
| | | * @throws TaskClientException if there is no task with the requested id |
| | | */ |
| | | public synchronized TaskEntry cancelTask(String id) |
| | | public synchronized void cancelTask(String id) |
| | | throws TaskClientException, IOException, ASN1Exception, LDAPException |
| | | { |
| | | LDAPReader reader = connection.getLDAPReader(); |
| | |
| | | LDAPAttribute attr = new LDAPAttribute(ATTR_TASK_STATE, values); |
| | | mods.add(new LDAPModification(ModificationType.REPLACE, attr)); |
| | | |
| | | // We have to reset the start time or the scheduler will |
| | | // reschedule to task. |
| | | // attr = new LDAPAttribute(ATTR_TASK_SCHEDULED_START_TIME); |
| | | // mods.add(new LDAPModification(ModificationType.DELETE, attr)); |
| | | |
| | | ModifyRequestProtocolOp modRequest = |
| | | new ModifyRequestProtocolOp(dn, mods); |
| | | LDAPMessage requestMessage = |
| | |
| | | LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | errorMessage); |
| | | } |
| | | } else if (TaskState.isRecurring(state)) { |
| | | |
| | | ASN1OctetString dn = new ASN1OctetString(entry.getDN().toString()); |
| | | DeleteRequestProtocolOp deleteRequest = |
| | | new DeleteRequestProtocolOp(dn); |
| | | |
| | | LDAPMessage requestMessage = new LDAPMessage( |
| | | nextMessageID.getAndIncrement(), deleteRequest, null); |
| | | |
| | | writer.writeMessage(requestMessage); |
| | | |
| | | LDAPMessage responseMessage = reader.readMessage(); |
| | | |
| | | if (responseMessage == null) { |
| | | Message message = ERR_TASK_CLIENT_UNEXPECTED_CONNECTION_CLOSURE.get(); |
| | | throw new LDAPException(UNAVAILABLE.getIntValue(), message); |
| | | } |
| | | |
| | | if (responseMessage.getProtocolOpType() != |
| | | LDAPConstants.OP_TYPE_DELETE_RESPONSE) |
| | | { |
| | | throw new LDAPException( |
| | | LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | ERR_TASK_CLIENT_INVALID_RESPONSE_TYPE.get( |
| | | responseMessage.getProtocolOpName())); |
| | | } |
| | | |
| | | DeleteResponseProtocolOp deleteResponse = |
| | | responseMessage.getDeleteResponseProtocolOp(); |
| | | Message errorMessage = deleteResponse.getErrorMessage(); |
| | | if (errorMessage != null) { |
| | | throw new LDAPException( |
| | | LDAPResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | errorMessage); |
| | | } |
| | | } else { |
| | | throw new TaskClientException( |
| | | ERR_TASK_CLIENT_UNCANCELABLE_TASK.get(id)); |
| | |
| | | throw new TaskClientException( |
| | | ERR_TASK_CLIENT_TASK_STATE_UNKNOWN.get(id)); |
| | | } |
| | | return getTaskEntry(id); |
| | | } |
| | | |
| | | |
| | |
| | | supAttrNames.add("ds-task-log-message"); |
| | | supAttrNames.add("ds-task-notify-on-completion"); |
| | | supAttrNames.add("ds-task-notify-on-error"); |
| | | supAttrNames.add("ds-recurring-task-id"); |
| | | supAttrNames.add("ds-recurring-task-schedule"); |
| | | } |
| | | |
| | | private String id; |
| | |
| | | private String schedStart; |
| | | private String actStart; |
| | | private String compTime; |
| | | private String schedTab; |
| | | private List<String> depends; |
| | | private String depFailAct; |
| | | private List<String> logs; |
| | |
| | | logs = getMultiStringValue(entry, p + "log-message"); |
| | | notifyErr = getMultiStringValue(entry, p + "notify-on-error"); |
| | | notifyComp = getMultiStringValue(entry, p + "notify-on-completion"); |
| | | schedTab = getSingleStringValue(entry, "ds-recurring-task-schedule"); |
| | | |
| | | |
| | | // Build a map of non-superior attribute value pairs for display |
| | |
| | | } |
| | | |
| | | /** |
| | | * Gets recurring schedule tab. |
| | | * |
| | | * @return Message tab string |
| | | */ |
| | | public Message getScheduleTab() { |
| | | return Message.raw(schedTab); |
| | | } |
| | | |
| | | /** |
| | | * Gets the IDs of tasks upon which this task depends. |
| | | * |
| | | * @return array of IDs |
| | |
| | | if (state != null) { |
| | | Task task = getTask(); |
| | | cancelable = (TaskState.isPending(state) || |
| | | TaskState.isRecurring(state) || |
| | | (TaskState.isRunning(state) && |
| | | task != null && |
| | | task.isInterruptable())); |
| | |
| | | |
| | | |
| | | /** |
| | | * Gets an arbitrary task id assigned to this task. |
| | | * |
| | | * @return assigned task id if any or <CODE>null</CODE> otherwise. |
| | | */ |
| | | String getTaskId(); |
| | | |
| | | |
| | | /** |
| | | * Gets the date/time pattern for recurring task schedule. |
| | | * |
| | | * @return recurring date/time pattern at which the task |
| | | * should be scheduled. |
| | | */ |
| | | String getRecurringDateTime(); |
| | | |
| | | |
| | | /** |
| | | * Gets a list of task IDs upon which this task is dependent. |
| | | * |
| | | * @return list of task IDs |
| | |
| | | // Argument for describing the task's start time |
| | | StringArgument startArg; |
| | | |
| | | // Argument to indicate a recurring task |
| | | StringArgument recurringArg; |
| | | |
| | | // Argument for specifying completion notifications |
| | | StringArgument completionNotificationArg; |
| | | |
| | |
| | | * @return LDAPConnectionArgumentParser for processing CLI input |
| | | */ |
| | | protected LDAPConnectionArgumentParser createArgParser(String className, |
| | | Message toolDescription) |
| | | { |
| | | Message toolDescription) |
| | | { |
| | | ArgumentGroup ldapGroup = new ArgumentGroup( |
| | | INFO_DESCRIPTION_TASK_LDAP_ARGS.get(), 1001); |
| | | INFO_DESCRIPTION_TASK_LDAP_ARGS.get(), 1001); |
| | | |
| | | argParser = new LDAPConnectionArgumentParser(className, |
| | | toolDescription, false, ldapGroup, alwaysSSL); |
| | | toolDescription, false, ldapGroup, alwaysSSL); |
| | | |
| | | ArgumentGroup taskGroup = new ArgumentGroup( |
| | | INFO_DESCRIPTION_TASK_TASK_ARGS.get(), 1000); |
| | | INFO_DESCRIPTION_TASK_TASK_ARGS.get(), 1000); |
| | | |
| | | try { |
| | | StringArgument propertiesFileArgument = new StringArgument( |
| | | "propertiesFilePath", |
| | | null, OPTION_LONG_PROP_FILE_PATH, |
| | | false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null, |
| | | INFO_DESCRIPTION_PROP_FILE_PATH.get()); |
| | | "propertiesFilePath", |
| | | null, OPTION_LONG_PROP_FILE_PATH, |
| | | false, false, true, INFO_PROP_FILE_PATH_PLACEHOLDER.get(), null, null, |
| | | INFO_DESCRIPTION_PROP_FILE_PATH.get()); |
| | | argParser.addArgument(propertiesFileArgument); |
| | | argParser.setFilePropertiesArgument(propertiesFileArgument); |
| | | |
| | | BooleanArgument noPropertiesFileArgument = new BooleanArgument( |
| | | "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE, |
| | | INFO_DESCRIPTION_NO_PROP_FILE.get()); |
| | | argParser.addArgument(noPropertiesFileArgument); |
| | | argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); |
| | | BooleanArgument noPropertiesFileArgument = new BooleanArgument( |
| | | "noPropertiesFileArgument", null, OPTION_LONG_NO_PROP_FILE, |
| | | INFO_DESCRIPTION_NO_PROP_FILE.get()); |
| | | argParser.addArgument(noPropertiesFileArgument); |
| | | argParser.setNoPropertiesFileArgument(noPropertiesFileArgument); |
| | | |
| | | startArg = new StringArgument( |
| | | OPTION_LONG_START_DATETIME, |
| | | OPTION_SHORT_START_DATETIME, |
| | | OPTION_LONG_START_DATETIME, false, false, |
| | | true, INFO_START_DATETIME_PLACEHOLDER.get(), |
| | | null, null, |
| | | INFO_DESCRIPTION_START_DATETIME.get()); |
| | | OPTION_LONG_START_DATETIME, |
| | | OPTION_SHORT_START_DATETIME, |
| | | OPTION_LONG_START_DATETIME, false, false, |
| | | true, INFO_START_DATETIME_PLACEHOLDER.get(), |
| | | null, null, |
| | | INFO_DESCRIPTION_START_DATETIME.get()); |
| | | argParser.addArgument(startArg, taskGroup); |
| | | |
| | | recurringArg = new StringArgument( |
| | | OPTION_LONG_RECURRING_TASK, |
| | | OPTION_SHORT_RECURRING_TASK, |
| | | OPTION_LONG_RECURRING_TASK, false, false, |
| | | true, INFO_RECURRING_TASK_PLACEHOLDER.get(), |
| | | null, null, |
| | | INFO_DESCRIPTION_RECURRING_TASK.get()); |
| | | argParser.addArgument(recurringArg, taskGroup); |
| | | |
| | | completionNotificationArg = new StringArgument( |
| | | OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL, |
| | | OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL, |
| | | OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL, |
| | | false, true, true, INFO_EMAIL_ADDRESS_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION.get()); |
| | | OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL, |
| | | OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL, |
| | | OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL, |
| | | false, true, true, INFO_EMAIL_ADDRESS_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION.get()); |
| | | argParser.addArgument(completionNotificationArg, taskGroup); |
| | | |
| | | errorNotificationArg = new StringArgument( |
| | | OPTION_LONG_ERROR_NOTIFICATION_EMAIL, |
| | | OPTION_SHORT_ERROR_NOTIFICATION_EMAIL, |
| | | OPTION_LONG_ERROR_NOTIFICATION_EMAIL, |
| | | false, true, true, INFO_EMAIL_ADDRESS_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION.get()); |
| | | OPTION_LONG_ERROR_NOTIFICATION_EMAIL, |
| | | OPTION_SHORT_ERROR_NOTIFICATION_EMAIL, |
| | | OPTION_LONG_ERROR_NOTIFICATION_EMAIL, |
| | | false, true, true, INFO_EMAIL_ADDRESS_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION.get()); |
| | | argParser.addArgument(errorNotificationArg, taskGroup); |
| | | |
| | | dependencyArg = new StringArgument( |
| | | OPTION_LONG_DEPENDENCY, |
| | | OPTION_SHORT_DEPENDENCY, |
| | | OPTION_LONG_DEPENDENCY, |
| | | false, true, true, INFO_TASK_ID_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_DEPENDENCY_ID.get()); |
| | | OPTION_LONG_DEPENDENCY, |
| | | OPTION_SHORT_DEPENDENCY, |
| | | OPTION_LONG_DEPENDENCY, |
| | | false, true, true, INFO_TASK_ID_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_DEPENDENCY_ID.get()); |
| | | argParser.addArgument(dependencyArg, taskGroup); |
| | | |
| | | Set fdaValSet = EnumSet.allOf(FailedDependencyAction.class); |
| | | failedDependencyActionArg = new StringArgument( |
| | | OPTION_LONG_FAILED_DEPENDENCY_ACTION, |
| | | OPTION_SHORT_FAILED_DEPENDENCY_ACTION, |
| | | OPTION_LONG_FAILED_DEPENDENCY_ACTION, |
| | | false, true, true, INFO_ACTION_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION.get( |
| | | StaticUtils.collectionToString(fdaValSet, ","), |
| | | FailedDependencyAction.defaultValue().name())); |
| | | OPTION_LONG_FAILED_DEPENDENCY_ACTION, |
| | | OPTION_SHORT_FAILED_DEPENDENCY_ACTION, |
| | | OPTION_LONG_FAILED_DEPENDENCY_ACTION, |
| | | false, true, true, INFO_ACTION_PLACEHOLDER.get(), |
| | | null, null, INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION.get( |
| | | StaticUtils.collectionToString(fdaValSet, ","), |
| | | FailedDependencyAction.defaultValue().name())); |
| | | argParser.addArgument(failedDependencyActionArg, taskGroup); |
| | | |
| | | testIfOfflineArg = new BooleanArgument( |
| | | "testIfOffline", null, "testIfOffline", |
| | | INFO_DESCRIPTION_TEST_IF_OFFLINE.get()); |
| | | "testIfOffline", null, "testIfOffline", |
| | | INFO_DESCRIPTION_TEST_IF_OFFLINE.get()); |
| | | testIfOfflineArg.setHidden(true); |
| | | argParser.addArgument(testIfOfflineArg); |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public String getRecurringDateTime() { |
| | | String pattern = null; |
| | | |
| | | // If the recurring task arg is present parse its value |
| | | if (recurringArg != null && recurringArg.isPresent()) { |
| | | pattern = recurringArg.getValue(); |
| | | } |
| | | return pattern; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public List<String> getDependencyIds() { |
| | | if (dependencyArg.isPresent()) { |
| | | return dependencyArg.getValues(); |
| | |
| | | TaskClient tc = new TaskClient(conn); |
| | | TaskEntry taskEntry = tc.schedule(this); |
| | | Message startTime = taskEntry.getScheduledStartTime(); |
| | | if (startTime == null || startTime.length() == 0) { |
| | | if (taskEntry.getTaskState() == TaskState.RECURRING) { |
| | | out.println( |
| | | wrapText(INFO_TASK_TOOL_RECURRING_TASK_SCHEDULED.get( |
| | | taskEntry.getType(), |
| | | taskEntry.getId()), |
| | | MAX_LINE_WIDTH)); |
| | | } else if (startTime == null || startTime.length() == 0) { |
| | | out.println( |
| | | wrapText(INFO_TASK_TOOL_TASK_SCHEDULED_NOW.get( |
| | | taskEntry.getType(), |
| | | taskEntry.getId()), |
| | | MAX_LINE_WIDTH)); |
| | | |
| | | } else { |
| | | out.println( |
| | | wrapText(INFO_TASK_TOOL_TASK_SCHEDULED_FUTURE.get( |
| | |
| | | |
| | | } while (!taskEntry.isDone()); |
| | | if (TaskState.isSuccessful(taskEntry.getTaskState())) { |
| | | out.println( |
| | | wrapText(INFO_TASK_TOOL_TASK_SUCESSFULL.get( |
| | | taskEntry.getType(), |
| | | taskEntry.getId()), |
| | | MAX_LINE_WIDTH)); |
| | | |
| | | if (taskEntry.getTaskState() != TaskState.RECURRING) { |
| | | out.println( |
| | | wrapText(INFO_TASK_TOOL_TASK_SUCESSFULL.get( |
| | | taskEntry.getType(), |
| | | taskEntry.getId()), |
| | | MAX_LINE_WIDTH)); |
| | | } |
| | | return 0; |
| | | } else { |
| | | out.println( |
| | |
| | | * cases that depend on this specific value of "o=test". |
| | | */ |
| | | public static final String TEST_ROOT_DN_STRING = "o=test"; |
| | | |
| | | |
| | | /** |
| | | * The backend if for the test backend |
| | | */ |
| | |
| | | * The string representation of the OpenDMK jar file location |
| | | * that will be used as base to determine if snmp is included or not |
| | | */ |
| | | public static final String PROPERTY_OPENDMK_LOCATION = |
| | | public static final String PROPERTY_OPENDMK_LOCATION = |
| | | "org.opends.server.snmp.opendmk"; |
| | | |
| | | /** |
| | |
| | | testInstallRoot.mkdirs(); |
| | | testInstanceRoot.mkdirs(); |
| | | } |
| | | |
| | | |
| | | File testInstanceSchema = |
| | | new File (testInstanceRoot, "config" + File.separator + "schema"); |
| | | testInstanceSchema.mkdirs(); |
| | |
| | | File testClassesDir = new File(testInstanceRoot, "classes"); |
| | | File testLibDir = new File(testInstallRoot, "lib"); |
| | | File testBinDir = new File(testInstallRoot, "bin"); |
| | | |
| | | |
| | | // Snmp resource |
| | | String opendmkJarFileLocation = |
| | | String opendmkJarFileLocation = |
| | | System.getProperty(PROPERTY_OPENDMK_LOCATION); |
| | | |
| | | |
| | | File opendmkJar = new File(opendmkJarFileLocation, "jdmkrt.jar"); |
| | | |
| | | |
| | | File snmpResourceDir = new File(buildRoot + File.separator + "src" + |
| | | File.separator + "snmp" + File.separator + |
| | | "resource"); |
| | | |
| | | |
| | | File snmpConfigDir = new File(snmpResourceDir, "config"); |
| | | |
| | | |
| | | File testSnmpResourceDir = new File (testConfigDir + File.separator + |
| | | "snmp"); |
| | | |
| | | |
| | | if (Boolean.getBoolean(PROPERTY_COPY_CLASSES_TO_TEST_PKG)) |
| | | { |
| | | copyDirectory(serverClassesDir, testClassesDir); |
| | | copyDirectory(unitClassesDir, testClassesDir); |
| | | } |
| | | |
| | | |
| | | if (installedRoot != null) |
| | | { |
| | | copyDirectory(new File(installedRoot), testInstallRoot); |
| | | |
| | | |
| | | // Get the instance location |
| | | |
| | | |
| | | } |
| | | else |
| | | { |
| | |
| | | DirectoryEnvironmentConfig config = new DirectoryEnvironmentConfig(); |
| | | config.setServerRoot(testInstallRoot); |
| | | config.setInstanceRoot(testInstanceRoot); |
| | | |
| | | |
| | | config.setForceDaemonThreads(true); |
| | | config.setConfigClass(ConfigFileHandler.class); |
| | | config.setConfigFile(new File(testConfigDir, "config.ldif")); |
| | |
| | | if (testConfigDir == null) { |
| | | throw new RuntimeException("The testConfigDir variable is not set yet!"); |
| | | } |
| | | |
| | | |
| | | return (testConfigDir); |
| | | } |
| | | |
| | |
| | | in.close(); |
| | | out.close(); |
| | | } |
| | | |
| | | |
| | | public static void appendFile(File src, File dst) throws IOException { |
| | | InputStream in = new FileInputStream(src); |
| | | OutputStream out = new FileOutputStream(dst, true); |
| | |
| | | in.close(); |
| | | out.close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Get the LDAP port the test environment Directory Server instance is |
| | |
| | | |
| | | |
| | | /** |
| | | * Adds the provided entry to the Directory Server using an internal |
| | | * operation. |
| | | * |
| | | * @param lines The lines that make up the entry to be added. |
| | | * |
| | | * @return result code for this operation. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | public static ResultCode addEntryOperation(String... lines) |
| | | throws Exception |
| | | { |
| | | Entry entry = makeEntry(lines); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | AddOperation addOperation = conn.processAdd(entry.getDN(), |
| | | entry.getObjectClasses(), |
| | | entry.getUserAttributes(), |
| | | entry.getOperationalAttributes()); |
| | | return addOperation.getResultCode(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds the provided set of entries to the Directory Server using internal |
| | | * operations. |
| | | * |
| | |
| | | "-a", |
| | | "-f", path |
| | | }; |
| | | |
| | | |
| | | if (useAdminPort) { |
| | | return LDAPModify.mainModify(adminArgs, false, null, null); |
| | | } else { |
| | |
| | | } catch (Exception e) { |
| | | hostName="Unknown (" + e + ")"; |
| | | } |
| | | |
| | | |
| | | String[] fullArgs = new String[args.length + 11]; |
| | | fullArgs[0] = "-h"; |
| | | fullArgs[1] = hostName; |
| | |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.GregorianCalendar; |
| | | import java.util.TimeZone; |
| | | |
| | | import java.util.UUID; |
| | | import org.testng.annotations.AfterClass; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.Test; |
| | |
| | | import org.opends.server.tasks.TasksTestCase; |
| | | import org.opends.server.types.DN; |
| | | |
| | | import org.opends.server.types.ResultCode; |
| | | import static org.testng.Assert.*; |
| | | |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | |
| | | |
| | |
| | | assertEquals(resultCode, 0); |
| | | assertFalse(DirectoryServer.entryExists(DN.decode(taskDN))); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests basic recurring task functionality and parser. |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testRecurringTask() |
| | | throws Exception |
| | | { |
| | | String taskID = "testRecurringTask"; |
| | | String taskDN = "ds-recurring-task-id=" + |
| | | taskID + ",cn=Recurring Tasks,cn=tasks"; |
| | | String taskSchedule = "00 * * * *"; |
| | | |
| | | String[] invalidTaskSchedules = { |
| | | "* * * *", "* * * * * *", "*:*:*:*:*", |
| | | "60 * * * *", "-1 * * * *", "1-60 * * * *", "1,60 * * * *", |
| | | "* 24 * * *", "* -1 * * *", "* 1-24 * * *", "* 1,24 * * *", |
| | | "* * 32 * *", "* * 0 * *", "* * 1-32 * *", "* * 1,32 * *", |
| | | "* * * 13 *", "* * * 0 *", "* * * 1-13 *", "* * * 1,13 *", |
| | | "* * * * 7", "* * * * -1", "* * * * 1-7", "* * * * 1,7", |
| | | "* * 31 2 *" }; |
| | | String[] validTaskSchedules = { |
| | | "* * * * *", |
| | | "59 * * * *", "0 * * * *", "0-59 * * * *", "0,59 * * * *", |
| | | "* 23 * * *", "* 0 * * *", "* 0-23 * * *", "* 0,23 * * *", |
| | | "* * 31 * *", "* * 1 * *", "* * 1-31 * *", "* * 1,31 * *", |
| | | "* * * 12 *", "* * * 1 *", "* * * 1-12 *", "* * * 1,12 *", |
| | | "* * * * 6", "* * * * 0", "* * * * 0-6", "* * * * 0,6" }; |
| | | |
| | | GregorianCalendar calendar = new GregorianCalendar(); |
| | | calendar.setFirstDayOfWeek(GregorianCalendar.SUNDAY); |
| | | calendar.setLenient(false); |
| | | calendar.add(GregorianCalendar.HOUR_OF_DAY, 1); |
| | | calendar.set(GregorianCalendar.MINUTE, 0); |
| | | calendar.set(GregorianCalendar.SECOND, 0); |
| | | |
| | | Date scheduledDate = calendar.getTime(); |
| | | String scheduledTaskID = taskID + " - " + scheduledDate.toString(); |
| | | String scheduledTaskDN = "ds-task-id=" + scheduledTaskID + |
| | | ",cn=Scheduled Tasks,cn=tasks"; |
| | | |
| | | assertTrue(addRecurringTask(taskID, taskSchedule)); |
| | | |
| | | Task scheduledTask = TasksTestCase.getTask(DN.decode(scheduledTaskDN)); |
| | | assertTrue(TaskState.isPending(scheduledTask.getTaskState())); |
| | | |
| | | // Perform a modification to update a non-state attribute. |
| | | int resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: " + taskDN, |
| | | "changetype: modify", |
| | | "replace: ds-recurring-task-schedule", |
| | | "ds-recurring-task-schedule: * * * * *"); |
| | | assertFalse(resultCode == 0); |
| | | |
| | | // Delete recurring task. |
| | | resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: " + taskDN, |
| | | "changetype: delete"); |
| | | assertEquals(resultCode, 0); |
| | | assertFalse(DirectoryServer.entryExists(DN.decode(taskDN))); |
| | | |
| | | // Make sure scheduled task got canceled. |
| | | scheduledTask = TasksTestCase.getTask(DN.decode(scheduledTaskDN)); |
| | | assertTrue(TaskState.isCancelled(scheduledTask.getTaskState())); |
| | | |
| | | // Test parser with invalid schedules. |
| | | for (String invalidSchedule : invalidTaskSchedules) { |
| | | assertFalse(addRecurringTask(taskID, invalidSchedule)); |
| | | } |
| | | |
| | | // Test parser with valid schedules. |
| | | for (String validSchedule : validTaskSchedules) { |
| | | taskID = "testRecurringTask" + "-" + UUID.randomUUID(); |
| | | taskDN = "ds-recurring-task-id=" + taskID + |
| | | ",cn=Recurring Tasks,cn=tasks"; |
| | | assertTrue(addRecurringTask(taskID, validSchedule)); |
| | | // Delete recurring task. |
| | | resultCode = TestCaseUtils.applyModifications(true, |
| | | "dn: " + taskDN, |
| | | "changetype: delete"); |
| | | assertEquals(resultCode, 0); |
| | | assertFalse(DirectoryServer.entryExists(DN.decode(taskDN))); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Adds recurring task to the task backend. |
| | | * |
| | | * @param taskID recurring task id. |
| | | * |
| | | * @param taskSchedule recurring task schedule. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | * |
| | | * @return <CODE>true</CODE> if task successfully added to |
| | | * the task backend, <CODE>false</CODE> otherwise. |
| | | */ |
| | | @Test(enabled=false) // This isn't a test method, but TestNG thinks it is. |
| | | private boolean addRecurringTask(String taskID, String taskSchedule) |
| | | throws Exception |
| | | { |
| | | String taskDN = "ds-recurring-task-id=" + |
| | | taskID + ",cn=Recurring Tasks,cn=tasks"; |
| | | |
| | | ResultCode rc = TestCaseUtils.addEntryOperation( |
| | | "dn: " + taskDN, |
| | | "objectClass: top", |
| | | "objectClass: ds-task", |
| | | "objectClass: ds-recurring-task", |
| | | "objectClass: extensibleObject", |
| | | "ds-recurring-task-id: " + taskID, |
| | | "ds-recurring-task-schedule: " + taskSchedule, |
| | | "ds-task-id: " + taskID, |
| | | "ds-task-class-name: org.opends.server.tasks.DummyTask", |
| | | "ds-task-dummy-sleep-time: 0"); |
| | | |
| | | if (rc != ResultCode.SUCCESS) { |
| | | return false; |
| | | } |
| | | return DirectoryServer.entryExists(DN.decode(taskDN)); |
| | | } |
| | | } |