001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.admin.client.cli; 018 019import static org.opends.messages.ToolMessages.*; 020import static com.forgerock.opendj.cli.ArgumentConstants.*; 021 022import java.text.ParseException; 023import java.util.Collections; 024import java.util.Date; 025import java.util.EnumSet; 026import java.util.List; 027import java.util.Set; 028 029import org.forgerock.util.Utils; 030import org.opends.server.backends.task.FailedDependencyAction; 031import org.opends.server.backends.task.RecurringTask; 032import org.opends.server.types.DirectoryException; 033import org.opends.server.util.StaticUtils; 034 035import com.forgerock.opendj.cli.Argument; 036import com.forgerock.opendj.cli.ArgumentException; 037import com.forgerock.opendj.cli.ReturnCode; 038import com.forgerock.opendj.cli.StringArgument; 039import com.forgerock.opendj.cli.ClientException; 040 041/** 042 * A class that contains all the arguments related to the task scheduling. 043 * 044 */ 045public class TaskScheduleArgs 046{ 047 /** 048 * Magic value used to indicate that the user would like to schedule 049 * this operation to run immediately as a task as opposed to running 050 * the operation in the local VM. 051 */ 052 public static final String NOW = "0"; 053 /** 054 * Argument for describing the task's start time. 055 */ 056 public StringArgument startArg; 057 058 /** 059 * Argument to indicate a recurring task. 060 */ 061 public StringArgument recurringArg; 062 063 /** 064 * Argument for specifying completion notifications. 065 */ 066 public StringArgument completionNotificationArg; 067 068 /** 069 * Argument for specifying error notifications. 070 */ 071 public StringArgument errorNotificationArg; 072 073 /** 074 * Argument for specifying dependency. 075 */ 076 public StringArgument dependencyArg; 077 078 /** 079 * Argument for specifying a failed dependency action. 080 */ 081 public StringArgument failedDependencyActionArg; 082 083 /** 084 * Default constructor. 085 */ 086 public TaskScheduleArgs() 087 { 088 try 089 { 090 createTaskArguments(); 091 } 092 catch (ArgumentException ae) 093 { 094 // This is a bug. 095 throw new RuntimeException("Unexpected error: "+ae, ae); 096 } 097 } 098 099 private void createTaskArguments() throws ArgumentException 100 { 101 startArg = 102 StringArgument.builder(OPTION_LONG_START_DATETIME) 103 .shortIdentifier(OPTION_SHORT_START_DATETIME) 104 .description(INFO_DESCRIPTION_START_DATETIME.get()) 105 .valuePlaceholder(INFO_START_DATETIME_PLACEHOLDER.get()) 106 .buildArgument(); 107 recurringArg = 108 StringArgument.builder(OPTION_LONG_RECURRING_TASK) 109 .shortIdentifier(OPTION_SHORT_RECURRING_TASK) 110 .description(INFO_DESCRIPTION_RECURRING_TASK.get()) 111 .valuePlaceholder(INFO_RECURRING_TASK_PLACEHOLDER.get()) 112 .buildArgument(); 113 completionNotificationArg = 114 StringArgument.builder(OPTION_LONG_COMPLETION_NOTIFICATION_EMAIL) 115 .shortIdentifier(OPTION_SHORT_COMPLETION_NOTIFICATION_EMAIL) 116 .description(INFO_DESCRIPTION_TASK_COMPLETION_NOTIFICATION.get()) 117 .multiValued() 118 .valuePlaceholder(INFO_EMAIL_ADDRESS_PLACEHOLDER.get()) 119 .buildArgument(); 120 errorNotificationArg = 121 StringArgument.builder(OPTION_LONG_ERROR_NOTIFICATION_EMAIL) 122 .shortIdentifier(OPTION_SHORT_ERROR_NOTIFICATION_EMAIL) 123 .description(INFO_DESCRIPTION_TASK_ERROR_NOTIFICATION.get()) 124 .multiValued() 125 .valuePlaceholder(INFO_EMAIL_ADDRESS_PLACEHOLDER.get()) 126 .buildArgument(); 127 dependencyArg = 128 StringArgument.builder(OPTION_LONG_DEPENDENCY) 129 .shortIdentifier(OPTION_SHORT_DEPENDENCY) 130 .description(INFO_DESCRIPTION_TASK_DEPENDENCY_ID.get()) 131 .multiValued() 132 .valuePlaceholder(INFO_TASK_ID_PLACEHOLDER.get()) 133 .buildArgument(); 134 135 final Set<FailedDependencyAction> fdaValSet = EnumSet.allOf(FailedDependencyAction.class); 136 failedDependencyActionArg = 137 StringArgument.builder(OPTION_LONG_FAILED_DEPENDENCY_ACTION) 138 .shortIdentifier(OPTION_SHORT_FAILED_DEPENDENCY_ACTION) 139 .description(INFO_DESCRIPTION_TASK_FAILED_DEPENDENCY_ACTION.get( 140 Utils.joinAsString(",", fdaValSet), FailedDependencyAction.defaultValue().name())) 141 .multiValued() 142 .valuePlaceholder(INFO_ACTION_PLACEHOLDER.get()) 143 .buildArgument(); 144 } 145 146 /** 147 * Returns all the task schedule related arguments. 148 * @return all the task schedule related arguments. 149 */ 150 public Argument[] getArguments() 151 { 152 return new Argument[] {startArg, recurringArg, completionNotificationArg, 153 errorNotificationArg, dependencyArg, failedDependencyActionArg}; 154 } 155 156 /** 157 * Validates arguments related to task scheduling. This should be 158 * called after the <code>ArgumentParser.parseArguments</code> has 159 * been called. 160 * <br> 161 * Note that this method does only validation that is not dependent on whether 162 * the operation will be launched as a task or not. If the operation is not 163 * to be launched as a task, the method {@link #validateArgsIfOffline()} 164 * should be called instead of this method. 165 * @throws ArgumentException if there is a problem with the arguments. 166 * @throws ClientException if there is a problem with one of the values provided 167 * by the user. 168 */ 169 public void validateArgs() throws ArgumentException, ClientException 170 { 171 if (startArg.isPresent() && !NOW.equals(startArg.getValue())) { 172 try { 173 Date date = StaticUtils.parseDateTimeString(startArg.getValue()); 174 // Check that the provided date is not previous to the current date. 175 Date currentDate = new Date(System.currentTimeMillis()); 176 if (currentDate.after(date)) 177 { 178 throw new ClientException(ReturnCode.ERROR_USER_DATA, ERR_START_DATETIME_ALREADY_PASSED.get( 179 startArg.getValue())); 180 } 181 } catch (ParseException pe) { 182 throw new ArgumentException(ERR_START_DATETIME_FORMAT.get()); 183 } 184 } 185 186 if (recurringArg.isPresent()) 187 { 188 try 189 { 190 RecurringTask.parseTaskTab(recurringArg.getValue()); 191 } 192 catch (DirectoryException de) 193 { 194 throw new ArgumentException(ERR_RECURRING_SCHEDULE_FORMAT_ERROR.get( 195 de.getMessageObject()), de); 196 } 197 } 198 199 checkEmailArgument(completionNotificationArg); 200 checkEmailArgument(errorNotificationArg); 201 202 if (failedDependencyActionArg.isPresent()) { 203 204 if (!dependencyArg.isPresent()) { 205 throw new ArgumentException(ERR_TASKTOOL_FDA_WITH_NO_DEPENDENCY.get()); 206 } 207 208 String fda = failedDependencyActionArg.getValue(); 209 if (null == FailedDependencyAction.fromString(fda)) { 210 Set<FailedDependencyAction> fdaValSet = 211 EnumSet.allOf(FailedDependencyAction.class); 212 throw new ArgumentException(ERR_TASKTOOL_INVALID_FDA.get(fda, 213 Utils.joinAsString(",", fdaValSet))); 214 } 215 } 216 } 217 218 private void checkEmailArgument(final StringArgument argument) throws ArgumentException { 219 if (argument.isPresent()) { 220 for (final String email : argument.getValues()) { 221 if (!StaticUtils.isEmailAddress(email)) { 222 throw new ArgumentException(ERR_TASKTOOL_INVALID_EMAIL_ADDRESS.get(email, argument.getLongIdentifier())); 223 } 224 } 225 } 226 } 227 228 /** 229 * Validates arguments related to task scheduling. This should be 230 * called after the <code>ArgumentParser.parseArguments</code> has 231 * been called. 232 * <br> 233 * This method assumes that the operation is not to be launched as a task. 234 * This method covers all the checks done by {@link #validateArgs()}, so it 235 * is not necessary to call that method if this method is being called. 236 * @throws ArgumentException if there is a problem with the arguments. 237 * @throws ClientException if there is a problem with one of the values provided 238 * by the user. 239 */ 240 public void validateArgsIfOffline() throws ArgumentException, ClientException 241 { 242 Argument[] incompatibleArgs = {startArg, recurringArg, 243 completionNotificationArg, 244 errorNotificationArg, dependencyArg, failedDependencyActionArg}; 245 for (Argument arg : incompatibleArgs) 246 { 247 if (arg.isPresent()) { 248 throw new ArgumentException(ERR_TASKTOOL_OPTIONS_FOR_TASK_ONLY.get( 249 arg.getLongIdentifier())); 250 } 251 } 252 validateArgs(); 253 } 254 255 /** 256 * Gets the date at which the associated task should be scheduled to start. 257 * 258 * @return date/time at which the task should be scheduled 259 */ 260 public Date getStartDateTime() { 261 Date start = null; 262 263 // If the start time arg is present parse its value 264 if (startArg != null && startArg.isPresent()) { 265 if (NOW.equals(startArg.getValue())) { 266 start = new Date(); 267 } else { 268 try { 269 start = StaticUtils.parseDateTimeString(startArg.getValue()); 270 } catch (ParseException pe) { 271 // ignore; validated in validateTaskArgs() 272 } 273 } 274 } 275 return start; 276 } 277 278 /** 279 * Whether the arguments provided by the user, indicate that the task should 280 * be executed immediately. 281 * <br> 282 * This method assumes that the arguments have already been parsed and 283 * validated. 284 * @return {@code true} if the task must be executed immediately and 285 * {@code false} otherwise. 286 */ 287 public boolean isStartNow() 288 { 289 boolean isStartNow = true; 290 if (startArg != null && startArg.isPresent()) { 291 isStartNow = NOW.equals(startArg.getValue()); 292 } 293 return isStartNow; 294 } 295 296 /** 297 * Gets the date/time pattern for recurring task schedule. 298 * 299 * @return recurring date/time pattern at which the task 300 * should be scheduled. 301 */ 302 public String getRecurringDateTime() { 303 String pattern = null; 304 305 // If the recurring task arg is present parse its value 306 if (recurringArg != null && recurringArg.isPresent()) { 307 pattern = recurringArg.getValue(); 308 } 309 return pattern; 310 } 311 312 /** 313 * Gets a list of task IDs upon which the associated task is dependent. 314 * 315 * @return list of task IDs 316 */ 317 public List<String> getDependencyIds() { 318 if (dependencyArg.isPresent()) { 319 return dependencyArg.getValues(); 320 } else { 321 return Collections.emptyList(); 322 } 323 } 324 325 /** 326 * Gets the action to take should one of the dependent task fail. 327 * 328 * @return action to take 329 */ 330 public FailedDependencyAction getFailedDependencyAction() { 331 FailedDependencyAction fda = null; 332 if (failedDependencyActionArg.isPresent()) { 333 String fdaString = failedDependencyActionArg.getValue(); 334 fda = FailedDependencyAction.fromString(fdaString); 335 } 336 return fda; 337 } 338 339 /** 340 * Gets a list of email address to which an email will be sent when this 341 * task completes. 342 * 343 * @return list of email addresses 344 */ 345 public List<String> getNotifyUponCompletionEmailAddresses() { 346 if (completionNotificationArg.isPresent()) { 347 return completionNotificationArg.getValues(); 348 } else { 349 return Collections.emptyList(); 350 } 351 } 352 353 /** 354 * Gets a list of email address to which an email will be sent if this 355 * task encounters an error during execution. 356 * 357 * @return list of email addresses 358 */ 359 public List<String> getNotifyUponErrorEmailAddresses() { 360 if (errorNotificationArg.isPresent()) { 361 return errorNotificationArg.getValues(); 362 } else { 363 return Collections.emptyList(); 364 } 365 } 366}