001 package edu.nrao.sss.model.project; 002 003 import java.util.ArrayList; 004 import java.util.List; 005 006 import edu.nrao.sss.model.project.scan.Scan; 007 import edu.nrao.sss.model.project.scan.ScanLoop; 008 import edu.nrao.sss.model.project.scan.ScanLoopValidator; 009 import edu.nrao.sss.validation.AbstractValidator; 010 import edu.nrao.sss.validation.FailureSeverity; 011 import edu.nrao.sss.validation.Validation; 012 import edu.nrao.sss.validation.ValidationFailure; 013 import edu.nrao.sss.validation.ValidationPurpose; 014 import edu.nrao.sss.validation.Validator; 015 016 /** 017 * A validator of {@link SchedulingBlock scheduling blocks}. 018 * <p> 019 * <u>Validations Performed for All Purposes</u> 020 * <ol> 021 * <li>Short name and/or long name was set.</li> 022 * <li>Scheduling block has at least one scan.</li> 023 * <li>Scan sequence is valid.<sup>1</sup></li> 024 * </ol> 025 * <sup>1</sup><i>The particular validations performed depend on the 026 * validator used by this one to operate on the target's scan 027 * sequence.</i></p> 028 * <p> 029 * <b>Version Info:</b> 030 * <table style="margin-left:2em"> 031 * <tr><td>$Revision: 2205 $</td></tr> 032 * <tr><td>$Date: 2009-04-16 12:29:48 -0600 (Thu, 16 Apr 2009) $</td></tr> 033 * <tr><td>$Author: btruitt $</td></tr> 034 * </table></p> 035 * 036 * @author David M. Harland 037 * @since 2007-02-09 038 */ 039 public class SchedulingBlockValidator 040 extends AbstractValidator<SchedulingBlock> 041 { 042 private ScanLoopValidator scanLoopValidator; 043 044 /** Creates a new instance. */ 045 public SchedulingBlockValidator() 046 { 047 super(SchedulingBlockValidator.class.getName(), SchedulingBlock.class); 048 } 049 050 public void setScanLoopValidator(ScanLoopValidator scanLoopValidator) 051 { 052 this.scanLoopValidator = scanLoopValidator; 053 } 054 055 /* (non-Javadoc) 056 * @see AbstractValidator#makeValidationList(ValidationPurpose) 057 */ 058 @Override 059 protected List<Validation<SchedulingBlock>> 060 makeValidationList(ValidationPurpose purpose) 061 { 062 List<Validation<SchedulingBlock>> validations = 063 new ArrayList<Validation<SchedulingBlock>>(); 064 065 validations.add(new HasName(this, purpose)); 066 validations.add(new HasScan(this, purpose)); 067 validations.add(new TimingValidation(this, purpose)); 068 validations.add(new HasValidCount(this, purpose)); 069 validations.add(new FixedDateHasStartTime(this, purpose)); 070 071 return validations; 072 } 073 074 /* (non-Javadoc) 075 * @see edu.nrao.sss.model.validation.AbstractValidator#validate() 076 */ 077 @Override 078 protected void validate() 079 { 080 super.validate(); 081 082 //Validate the scan sequence 083 ScanLoopValidator slv = (ScanLoopValidator)getScanLoopValidator(); 084 slv.setSkipOutermostLoop(true); 085 failures.addAll(slv.validate(target.getScanSequence(), purpose)); 086 } 087 088 //============================================================================ 089 // COMPONENT VALIDATORS 090 //============================================================================ 091 092 /** Returns a validator for program blocks. */ 093 public Validator getScanLoopValidator() 094 { 095 Validator validator = scanLoopValidator; 096 097 if (validator == null) 098 { 099 if (manager != null) 100 validator = manager.getValidator(ScanLoop.class); 101 102 if (validator == null) 103 validator = new ScanLoopValidator(); 104 } 105 106 return validator; 107 } 108 109 //============================================================================ 110 // 111 //============================================================================ 112 113 /** Make sure one or both of shortName & longName have been entered. */ 114 class HasName extends HasNameValidation<SchedulingBlock> 115 { 116 protected HasName(AbstractValidator<SchedulingBlock> validationContainer, 117 ValidationPurpose reasonForValidation) 118 { 119 super(validationContainer, reasonForValidation, "scheduling blocks"); 120 } 121 122 /** This test is passed if at least one name is not in default state. */ 123 @Override 124 protected boolean passesTest() 125 { 126 return !target.getName().equals(SchedulingBlock.DEFAULT_NAME); 127 } 128 } 129 130 //============================================================================ 131 // ENSURE SCHEDULING BLOCK HAS SCANS 132 //============================================================================ 133 134 /** Make sure scheduling block has at least 1 scan. */ 135 class HasScan extends Validation<SchedulingBlock> 136 { 137 protected HasScan(AbstractValidator<SchedulingBlock> validationContainer, 138 ValidationPurpose reasonForValidation) 139 { 140 super(validationContainer, reasonForValidation); 141 142 severity = 143 (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ? 144 FailureSeverity.ERROR : FailureSeverity.WARNING; 145 } 146 147 /** This test is passed if SB has > 0 scans. */ 148 @Override 149 protected boolean passesTest() 150 { 151 return target.getScanSequence().size() > 0; 152 } 153 154 /* (non-Javadoc) 155 * @see edu.nrao.sss.validation.Validation#displayMessage() 156 */ 157 @Override 158 protected String displayMessage() 159 { 160 StringBuilder buff = new StringBuilder("Scheduling block '"); 161 162 buff.append(target.getName()).append("' has no scans. "); 163 164 if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE) 165 { 166 buff.append("A scheduling block must have at least one scan") 167 .append(" in order to be executed. Please add a scan to this") 168 .append(" scheduling block, or remove this scheduling block from") 169 .append(" its program block."); 170 } 171 else 172 { 173 buff.append("This is fine for now, but you will need to add at least") 174 .append(" one scan before this scheduling block is ready") 175 .append(" for execution."); 176 } 177 178 return buff.toString(); 179 } 180 181 /* (non-Javadoc) 182 * @see edu.nrao.sss.validation.Validation#debugMessage() 183 */ 184 @Override 185 protected String debugMessage() 186 { 187 StringBuilder buff = new StringBuilder("SchedBlock '"); 188 189 buff.append(target.getName()).append("' has no scans."); 190 191 return buff.toString(); 192 } 193 } 194 195 /** Makes sure scheduling block has a start time specified iff it has a type of FIXED_DATE. */ 196 class FixedDateHasStartTime extends Validation<SchedulingBlock> 197 { 198 protected FixedDateHasStartTime(AbstractValidator<SchedulingBlock> validationContainer, 199 ValidationPurpose reasonForValidation) 200 { 201 super(validationContainer, reasonForValidation); 202 203 severity = 204 (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ? 205 FailureSeverity.ERROR : FailureSeverity.WARNING; 206 } 207 208 /** Makes sure scheduling block has a start time specified iff it has a type of FIXED_DATE. */ 209 @Override 210 protected boolean passesTest() 211 { 212 if (target.getType().equals(SchedulingType.FIXED_DATE)) 213 return target.hasFixedStartTime(); 214 215 else 216 return !target.hasFixedStartTime(); 217 } 218 219 /* (non-Javadoc) 220 * @see edu.nrao.sss.validation.Validation#displayMessage() 221 */ 222 @Override 223 protected String displayMessage() 224 { 225 StringBuilder buff = new StringBuilder("Scheduling block '"); 226 227 buff.append(target.getName()).append("' must have a start time specified if the scheduling type is fixed date and it must NOT have a start time specified otherwise. "); 228 229 if (purpose != ValidationPurpose.CERTIFY_READY_TO_USE) 230 { 231 buff.append("This is fine for now, but you will need to address this") 232 .append(" before this scheduling block is ready for execution."); 233 } 234 235 return buff.toString(); 236 } 237 238 /* (non-Javadoc) 239 * @see edu.nrao.sss.validation.Validation#debugMessage() 240 */ 241 @Override 242 protected String debugMessage() 243 { 244 StringBuilder buff = new StringBuilder("Scheduling block '"); 245 246 buff.append(target.getName()).append("' must have a start time specified if the scheduling type is fixed date and it must NOT have a start time specified otherwise. "); 247 return buff.toString(); 248 } 249 } 250 251 /** 252 * Authorized Count must be greater than 1, and for fixed scheduled SB's it 253 * must be exactly 1. 254 */ 255 class HasValidCount extends Validation<SchedulingBlock> 256 { 257 protected HasValidCount(AbstractValidator<SchedulingBlock> validationContainer, 258 ValidationPurpose reasonForValidation) 259 { 260 super(validationContainer, reasonForValidation); 261 262 severity = 263 (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ? 264 FailureSeverity.ERROR : FailureSeverity.WARNING; 265 } 266 267 /** This test is passed if SB's authorized count is > 0. */ 268 @Override 269 protected boolean passesTest() 270 { 271 if (!target.getExecutionStatus().isFinal()) 272 { 273 if (target.mayBeScheduledDynamically()) 274 return target.getAuthorizedCount() > 0; 275 else 276 return target.getAuthorizedCount() == 1; 277 } 278 279 return true; 280 281 //Note: for fixed-date we could allow count > 1 if and only if 282 //SB has no start-time scans, no stop-time scans, and the 283 //iterations are to be run consecutively. 284 } 285 286 /* (non-Javadoc) 287 * @see edu.nrao.sss.validation.Validation#displayMessage() 288 */ 289 @Override 290 protected String displayMessage() 291 { 292 StringBuilder buff = new StringBuilder("Scheduling block '"); 293 294 buff.append(target.getName()).append("' has an authorized count of "); 295 buff.append(target.getAuthorizedCount()); 296 297 if (target.mayBeScheduledDynamically()) 298 buff.append(". It should be > 0. "); 299 else 300 buff.append(". It should be 1"); 301 302 if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE) 303 { 304 buff.append("Please set a valid athorized count for this") 305 .append(" scheduling block, or remove this scheduling block from") 306 .append(" its program block."); 307 } 308 else 309 { 310 buff.append("This is fine for now, but you will need to set a valid") 311 .append(" authorized count before this scheduling block is ready") 312 .append(" for execution."); 313 } 314 315 return buff.toString(); 316 } 317 318 /* (non-Javadoc) 319 * @see edu.nrao.sss.validation.Validation#debugMessage() 320 */ 321 @Override 322 protected String debugMessage() 323 { 324 StringBuilder buff = new StringBuilder("Scheduling block '"); 325 326 buff.append(target.getName()).append("' has an authorized count of "); 327 buff.append(target.getAuthorizedCount()); 328 329 /* 330 if (is fixed scheduled) 331 buff.append(". It should be 1"); 332 333 else 334 */ 335 buff.append(". It should be > 0"); 336 337 return buff.toString(); 338 } 339 } 340 341 /** 342 * Validates the structure of the scans and loops held by this SB. 343 * Validations: 344 * 1) dynamically scheduled SB's have no stop-time scans 345 * 2) make sure a stop-time scan doesn't cut the previous scan short 346 * 3) stop-time scans are not allowed inside loops w/ iteration counts greater than 1. 347 */ 348 class TimingValidation extends Validation<SchedulingBlock> 349 { 350 private ScanTimingValidationHelper helper = new ScanTimingValidationHelper(); 351 private List<Scan> stopTimeScansInLoops = new ArrayList<Scan>(); 352 353 protected TimingValidation(AbstractValidator<SchedulingBlock> validationContainer, 354 ValidationPurpose reasonForValidation) 355 { 356 super(validationContainer, reasonForValidation); 357 358 severity = 359 (reasonForValidation == ValidationPurpose.CERTIFY_READY_TO_USE) ? 360 FailureSeverity.ERROR : FailureSeverity.WARNING; 361 } 362 363 /** 364 * Validations: 365 * 1) dynamically scheduled SB's have no stop-time scans 366 * 2) make sure a stop-time scan doesn't cut the previous scan short 367 * 3) stop-time scans are not allowed inside loops w/ iteration counts greater than 1. 368 */ 369 @Override 370 protected boolean passesTest() 371 { 372 List<Scan> scans = target.getScanSequence().toScanList(); 373 int n = scans.size(); 374 for (int i = 0; i < n; i++) 375 { 376 Scan s = scans.get(i); 377 if (s.getTimeSpec().isStopTime()) 378 { 379 for (int j = i + 1; j < n; j++) 380 { 381 if (s.equals(scans.get(j))) 382 { 383 this.stopTimeScansInLoops.add(s); 384 } 385 } 386 } 387 } 388 389 /* 390 The validation helper class will issue warnings that are meant to just 391 be warnings even if the ValidationPurpose is CERTIFY_READY_TO_USE. So 392 we make sure we keep this test's overall severity at the warning level 393 unless we get a real error. 394 */ 395 if (this.stopTimeScansInLoops.isEmpty()) 396 { 397 this.helper.validateScanTiming(target); 398 399 if (purpose == ValidationPurpose.CERTIFY_READY_TO_USE) 400 { 401 // default severity to WARNING unless one of these failures is higher than a warning. 402 severity = FailureSeverity.WARNING; 403 for (ValidationFailure f : this.helper.getValidationFailures()) 404 { 405 FailureSeverity fsev = f.getSeverity(); 406 if (FailureSeverity.ERROR == fsev || FailureSeverity.FATAL == fsev) 407 { 408 severity = FailureSeverity.ERROR; 409 break; 410 } 411 } 412 } 413 } 414 415 return this.stopTimeScansInLoops.isEmpty() && this.helper.getValidationFailures().isEmpty(); 416 } 417 418 /* (non-Javadoc) 419 * @see edu.nrao.sss.validation.Validation#displayMessage() 420 */ 421 @Override 422 protected String displayMessage() 423 { 424 StringBuilder buff = new StringBuilder(); 425 426 if (!this.stopTimeScansInLoops.isEmpty()) 427 { 428 buff = new StringBuilder("The following Scans in Scheduling block '"); 429 buff.append(target.getName()).append("' have a Stop Time specified but are inside a loop: "); 430 431 for (Scan s : this.stopTimeScansInLoops) 432 { 433 buff.append(s.getName()); 434 buff.append(", "); 435 } 436 437 // remove the last ", " 438 int len = buff.length(); 439 buff.delete(len - 2, len); 440 441 buff.append("."); 442 } 443 444 // The above errors preclude these errors from even being checked for. 445 else if (!this.helper.getValidationFailures().isEmpty()) 446 { 447 buff.append("Scheduling Block '"); 448 buff.append(target.getName()).append("' may be invalid for the following reasons: "); 449 450 for (ValidationFailure f : this.helper.getValidationFailures()) 451 { 452 buff.append(f.getDisplayMessage()); 453 buff.append(" "); 454 } 455 } 456 457 return buff.toString(); 458 } 459 460 /* (non-Javadoc) 461 * @see edu.nrao.sss.validation.Validation#debugMessage() 462 */ 463 @Override 464 protected String debugMessage() 465 { 466 return displayMessage(); 467 } 468 } 469 }