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