001 package edu.nrao.sss.model.project; 002 003 import java.math.BigDecimal; 004 import java.util.*; 005 006 import edu.nrao.sss.astronomy.CelestialCoordinateSystem; 007 import edu.nrao.sss.measure.*; 008 import edu.nrao.sss.model.project.scan.*; 009 import edu.nrao.sss.model.resource.*; 010 import edu.nrao.sss.model.resource.evla.EvlaPointingPosition; 011 import edu.nrao.sss.util.EnumerationUtility; 012 import edu.nrao.sss.util.IllegalTransitionException; 013 014 import edu.nrao.sss.model.project.scheduling.priority.Priority; 015 import edu.nrao.sss.model.project.scheduling.priority.PriorityType; 016 017 /** 018 * Helper for test classes; builds projects and their components. 019 * <p> 020 * <b>Version Info:</b> 021 * <table style="margin-left:2em"> 022 * <tr><td>$Revision: 2190 $</td></tr> 023 * <tr><td>$Date: 2009-04-13 15:15:03 -0600 (Mon, 13 Apr 2009) $</td></tr> 024 * <tr><td>$Author: dharland $</td></tr> 025 * </table></p> 026 * 027 * @since 2006-10-09 028 */ 029 public class ProjectBuilder 030 { 031 private static final EnumerationUtility ENUM_UTIL = 032 EnumerationUtility.getSharedInstance(); 033 034 private Random random = new Random(System.currentTimeMillis()); 035 036 private static int PROJECT_COUNTER = 0; 037 038 private boolean setId = false; 039 private Long nextProjectId = 1L; 040 private Long nextProgBlockId = 1L; 041 private Long nextSchedBlockId = 1L; 042 043 private ScanBuilder scanBuilder = new ScanBuilder(); 044 045 //Used for coordinating multiple intervals 046 private Date timeIntervalEnd = null; 047 048 //============================================================================ 049 // PUBLIC METHODS 050 //============================================================================ 051 052 /** 053 * Tells the factory methods whether or not they should set the object 054 * identifiers. 055 */ 056 public void setIdentifiers(boolean setIds) 057 { 058 setId = setIds; 059 } 060 061 public Project makeProject(TelescopeType telescope) 062 { 063 Project project = (telescope == null) ? makeProject() 064 : Project.createProject(telescope); 065 066 buildProject(project); 067 068 return project; 069 } 070 071 private Project makeProject() 072 { 073 return Project.createProject(random.nextDouble() < 0.2 ? TelescopeType.GBT 074 : TelescopeType.VLA); 075 } 076 077 public void buildProject(Project project) 078 { 079 if (project == null) 080 project = makeProject(); 081 082 if (setId) 083 project.setId(nextProjectId++); 084 085 Date now = new Date(); 086 project.setCreatedOn(now); 087 project.setLastUpdatedOn(now); 088 089 long id = 1L + (long)(random.nextInt(1000)); 090 project.setCreatedBy(id); 091 project.setLastUpdatedBy(id); 092 project.setEditor(id); 093 094 project.setTitle("SSS Random Project #" + (++PROJECT_COUNTER)); 095 project.setProjectCode(makeCode()); 096 project.setProposalCode(makeCode()); 097 project.setProjectType(ENUM_UTIL.getRandomValueFor(ProjectType.class)); 098 project.setScientificPriority( 099 ENUM_UTIL.getRandomValueFor(ScientificPriority.class)); 100 project.setAllocatedTime(10.0 + (double)(random.nextInt(50))); 101 setComment(project); 102 103 //Program Blocks 104 int pbCount = 1; 105 if (project.getTelescope().equals(TelescopeType.VLA)) 106 pbCount = 1 + random.nextInt(4); 107 108 for (int i=0; i < pbCount; i++) 109 makeProgramBlockFor(project); 110 111 //Make all PBs prerequisites of the last PB 112 if (pbCount > 1) 113 { 114 List<ProgramBlock> progBlocks = project.getProgramBlocks(); 115 ProgramBlock lastPb = progBlocks.get(pbCount - 1); 116 for (int pb=0; pb < (pbCount-1); pb++) 117 lastPb.addPrerequisite(progBlocks.get(pb)); 118 } 119 } 120 121 //---------------------------------------------------------------------------- 122 // Program Block 123 //---------------------------------------------------------------------------- 124 125 public ProgramBlock makeProgramBlockFor(Project proj) 126 { 127 //Quick exit if PB is null 128 if (proj == null) 129 return makeProgramBlock(); 130 131 ProgramBlock pb = proj.createProgramBlock(); 132 133 proj.addProgramBlock(pb); 134 135 fillProgramBlock(pb, true); 136 137 return pb; 138 } 139 140 public ProgramBlock makeProgramBlockButNotSchedulingBlocksFor(Project proj) 141 { 142 //Quick exit if PB is null 143 if (proj == null) 144 return makeProgramBlock(); 145 146 ProgramBlock pb = proj.createProgramBlock(); 147 148 proj.addProgramBlock(pb); 149 150 fillProgramBlock(pb, false); 151 152 return pb; 153 } 154 155 public ProgramBlock makeProgramBlock() 156 { 157 ProgramBlock pb = new ProgramBlock(); 158 159 fillProgramBlock(pb, true); 160 161 return pb; 162 } 163 164 public ProgramBlock makeProgramBlockButNotSchedulingBlocks() 165 { 166 ProgramBlock pb = new ProgramBlock(); 167 168 fillProgramBlock(pb, false); 169 170 return pb; 171 } 172 173 public void fillProgramBlock(ProgramBlock pb, boolean makeSbs) 174 { 175 if (setId) 176 pb.setId(nextProgBlockId++); 177 178 Date now = new Date(); 179 pb.setCreatedOn(now); 180 pb.setLastUpdatedOn(now); 181 182 long id = 1L + (long)(random.nextInt(1000)); 183 pb.setCreatedBy(id); 184 pb.setLastUpdatedBy(id); 185 186 pb.setName(makeCode()); 187 setComment(pb); 188 189 //Acceptable Telescope Configurations 190 List<TelescopeConfiguration> configurations = pb.getAcceptableConfigurations(); 191 int count = 1 + random.nextInt(4); 192 for (int tc=0; tc < count; tc++) 193 configurations.add(ENUM_UTIL.getRandomValueFor(TelescopeConfiguration.class)); 194 195 //Scheduling Blocks 196 count = makeSbs ? 1 + random.nextInt(4) : 0; 197 for (int i=0; i < count; i++) 198 makeSchedulingBlockFor(pb); 199 200 //Make all SBs prerequisites of the last SB 201 if (count > 1) 202 { 203 List<SchedulingBlock> schedBlocks = pb.getSchedulingBlocks(); 204 SchedulingBlock lastSb = schedBlocks.get(count - 1); 205 for (int s=0; s < (count-1); s++) 206 lastSb.addPrerequisite(schedBlocks.get(s)); 207 } 208 } 209 210 //---------------------------------------------------------------------------- 211 // Scheduling Block 212 //---------------------------------------------------------------------------- 213 214 public SchedulingBlock makeSchedulingBlockFor(ProgramBlock progBlock) 215 { 216 //Quick exit if PB is null 217 if (progBlock == null) 218 return makeSchedulingBlock(); 219 220 SchedulingBlock sb = progBlock.createSchedulingBlock(); 221 222 progBlock.addSchedulingBlock(sb); 223 224 fillSchedulingBlock(sb, true); 225 226 return sb; 227 } 228 229 public SchedulingBlock makeSchedulingBlockButNotScansFor(ProgramBlock progBlock) 230 { 231 //Quick exit if PB is null 232 if (progBlock == null) 233 return makeSchedulingBlock(); 234 235 SchedulingBlock sb = progBlock.createSchedulingBlock(); 236 237 progBlock.addSchedulingBlock(sb); 238 239 fillSchedulingBlock(sb, false); 240 241 return sb; 242 } 243 244 public SchedulingBlock makeSchedulingBlock() 245 { 246 SchedulingBlock sb = new SchedulingBlock(); 247 248 fillSchedulingBlock(sb, true); 249 250 return sb; 251 } 252 253 public SchedulingBlock makeSchedulingBlockButNotScans() 254 { 255 SchedulingBlock sb = new SchedulingBlock(); 256 257 fillSchedulingBlock(sb, false); 258 259 return sb; 260 } 261 262 public void fillSchedulingBlock(SchedulingBlock sb, boolean makeScans) 263 { 264 if (setId) 265 sb.setId(nextSchedBlockId++); 266 267 Date now = new Date(); 268 sb.setCreatedOn(now); 269 sb.setLastUpdatedOn(now); 270 271 long id = 1L + (long)(random.nextInt(1000)); 272 sb.setCreatedBy(id); 273 sb.setLastUpdatedBy(id); 274 275 sb.setName(makeCode()); 276 setComment(sb); 277 278 sb.setAuthorizedCount(1 + random.nextInt(5)); 279 sb.setType(ENUM_UTIL.getRandomValueFor(SchedulingType.class)); 280 if (sb.getType().equals(SchedulingType.FIXED_DATE)) 281 sb.setFixedStartTime(new Date()); 282 283 sb.setLstStartRange(makeTimeOfDayInterval()); 284 285 //Priorities 286 List<Priority> priorities = new ArrayList<Priority>(); 287 PriorityType[] types = PriorityType.values(); 288 final int priorityNormalizer = 8; 289 for ( PriorityType pt : types ){ 290 Priority priority = new Priority(); 291 priority.setPriorityType( pt ); 292 priority.setPriorityValue( random.nextFloat() * priorityNormalizer ); 293 priorities.add( priority ); 294 } 295 sb.setPriorities( priorities ); 296 297 //PreCalibrations 298 List<ServiceCalibration> calibs = sb.getServiceCalibrations(); 299 int count = random.nextInt(4); 300 for (int sc=0; sc < count; sc++) 301 { 302 ServiceCalibration calib = new ServiceCalibration(); 303 calib.setType(ENUM_UTIL.getRandomValueFor(ScanIntent.class)); 304 calib.setTiming(ENUM_UTIL.getRandomValueFor(ServiceCalibrationTiming.class)); 305 calib.setAllowableSeparation(new TimeDuration(new BigDecimal(20 + random.nextInt(80)))); 306 calibs.add(calib); 307 } 308 309 //Assumed telescope position 310 if (random.nextBoolean()) 311 { 312 EvlaPointingPosition antPos = new EvlaPointingPosition(); 313 314 antPos.setCoordinateSystem(ENUM_UTIL.getRandomValueFor(CelestialCoordinateSystem.class)); 315 316 int minAngle = antPos.getLatitudeMinimum().toUnits(ArcUnits.DEGREE).intValue(); 317 int maxAngle = antPos.getLatitudeMaximum().toUnits(ArcUnits.DEGREE).intValue(); 318 319 int angle = random.nextInt(maxAngle - minAngle) + minAngle; 320 321 antPos.setLatitude(new Angle(""+angle)); 322 323 minAngle = antPos.getLongitudeMinimum().toUnits(ArcUnits.DEGREE).intValue(); 324 maxAngle = antPos.getLongitudeMaximum().toUnits(ArcUnits.DEGREE).intValue(); 325 326 angle = random.nextInt(maxAngle - minAngle) + minAngle; 327 328 antPos.setLongitude(new Angle(""+angle)); 329 330 sb.setAssumedTelescopePointing(antPos); 331 } 332 333 //TODO Environmental Constraints 334 335 sb.setPreferredDateRange(makeTimeInterval(null)); 336 337 //Scans 338 if (makeScans) 339 makeScansFor(sb); 340 } 341 342 //---------------------------------------------------------------------------- 343 // Execution Block 344 //---------------------------------------------------------------------------- 345 346 public ExecutionBlock makeExecutionBlock() 347 { 348 SchedulingBlock sb = makeSchedulingBlockButNotScans(); 349 sb.setAuthorizedCount(1); 350 sb.submit(); 351 352 //Status will be not-yet-scheduled 353 ExecutionBlock eb = sb.getExecutionBlocks().iterator().next(); 354 355 try 356 { //not-yet-sched = 0.2000 357 if (random.nextDouble() < 0.8) 358 { 359 double d = random.nextDouble(); 360 if (d < 0.1) //Hold 361 { 362 eb.updateStatusHold(); //on-hold = 0.8 * 0.1 * 0.5 = 0.0400 363 364 if (random.nextBoolean()) 365 eb.updateStatusRelease(); //not-yet-sched = 0.8 * 0.1 * 0.5 = 0.0400 366 } 367 else if (d < 0.2) //Cancel 368 { 369 eb.updateStatusCancel(); //canceled = 0.8 * 0.1 = 0.0800 370 } 371 else //Schedule (0.64) 372 { 373 eb.updateStatusSchedule(); //scheduled = 0.64 * 0.2 = 0.1280 374 375 d = random.nextDouble(); 376 377 if (d < 0.1) //Hold 378 { 379 eb.updateStatusHold(); //on-hold = 0.64 * 0.1 * 0.5 = 0.0320 380 381 if (random.nextBoolean()) //not-yet-sched = 0.64 * 0.1 * 0.5 = 0.0320 382 eb.updateStatusRelease(); 383 } 384 else if (d < 0.2) //Cancel 385 { 386 eb.updateStatusCancel(); //canceled = 0.64 * 0.1 = 0.0640 387 } 388 else if (d < 0.8) //Execute 389 { 390 eb.updateStatusExecute(); //in-progress = 0.64 * 0.6 * 0.2 = 0.0768 391 392 d = random.nextDouble(); 393 394 if (d < 0.1) eb.updateStatusFail(); //= 0.64 * 0.6 * 0.1 = 0.0384 395 else if (d < 0.2) eb.updateStatusCancel(); //= 0.64 * 0.6 * 0.1 = 0.0384 396 else if (d < 0.8) eb.updateStatusComplete(); //= 0.64 * 0.6 * 0.6 = 0.2304 397 398 } 399 } 400 } 401 } 402 catch (IllegalTransitionException ex) 403 { 404 throw new RuntimeException("PROGRAMMER ERROR in ProjectBuilder.makeExecutionBlock().", ex); 405 } 406 407 eb.setComments(makeComment()); 408 409 return eb; 410 } 411 412 //---------------------------------------------------------------------------- 413 // Scan 414 //---------------------------------------------------------------------------- 415 416 public void makeScansFor(SchedulingBlock schedBlock) 417 { 418 scanBuilder.makeScansFor(schedBlock.getScanSequence()); 419 } 420 421 public Scan makeScanFor(SchedulingBlock schedBlock) 422 { 423 return scanBuilder.makeScanFor(schedBlock.getScanSequence()); 424 } 425 426 private static final String[] COMMENTS = 427 { 428 "I can't believe they approved my proposal.", 429 "Life was easier before they invented computers.", 430 "Where do I find the headset for listening to my observation?", 431 "How many channels can I get on these big dishes?", 432 "No comment." 433 }; 434 435 private static final String[] COMMENTS_TO_OPER = 436 { 437 "Operator, well let's forget about this call.", 438 "Operator, get me the police!", 439 "Hello, operator, give me number nine.", 440 "Thank you for your time. Oh, you've been so much more than kind. You can keep the dime.", 441 "Smooth operator. Smooth operator." 442 }; 443 444 /** Sometimes sets comment, sometimes removes comments. */ 445 public void setComment(Project project) 446 { 447 project.setComments(makeComment()); 448 } 449 450 /** Sometimes sets comment, sometimes removes comments. */ 451 public void setComment(ProgramBlock progBlock) 452 { 453 progBlock.setComments(makeComment()); 454 } 455 456 /** Sometimes sets comment, sometimes removes comments. */ 457 public void setComment(SchedulingBlock schedBlock) 458 { 459 schedBlock.setComments(makeComment()); 460 } 461 462 private String makeComment() 463 { 464 int size = COMMENTS.length; 465 int index = random.nextInt(2 * size); 466 467 return index < size ? COMMENTS[index] : null; 468 } 469 470 /** Sometimes sets comment, sometimes removes comments. */ 471 public void setCommentToOperator(SchedulingBlock sb) 472 { 473 int size = COMMENTS_TO_OPER.length; 474 int index = random.nextInt(2 * size); 475 476 sb.setCommentsToOperator(index < size ? COMMENTS_TO_OPER[index] : null); 477 } 478 479 //============================================================================ 480 // HELPERS 481 //============================================================================ 482 483 private String makeCode() 484 { 485 StringBuilder srcName = new StringBuilder(); 486 487 int numChars = random.nextInt(3)+3; 488 for (int i=0; i < numChars; i++) 489 srcName.append((char)('a'+random.nextInt(25))); 490 491 return srcName.toString(); 492 } 493 494 private TimeOfDay makeTimeOfDay() 495 { 496 TimeOfDay tod = new TimeOfDay(); 497 498 int seconds = random.nextInt(tod.getLengthOfDay() 499 .toUnits(TimeUnits.SECOND).intValue()); 500 tod.set(new BigDecimal(seconds)); 501 502 return tod; 503 } 504 505 private TimeOfDayInterval makeTimeOfDayInterval() 506 { 507 return new TimeOfDayInterval(makeTimeOfDay(), makeTimeOfDay()); 508 } 509 510 private TimeInterval makeTimeInterval(Date startTime) 511 { 512 int year, month, day; 513 Date from; 514 Calendar cal = Calendar.getInstance(); 515 516 if (startTime == null) 517 { 518 year = 1950 + random.nextInt(55); 519 month = random.nextInt(12); 520 day = 1 + random.nextInt(27); 521 cal.set(year, month, day); 522 from = cal.getTime(); 523 } 524 else 525 { 526 from = startTime; 527 } 528 529 year = 2006 + random.nextInt(100); 530 month = random.nextInt(12); 531 day = 1 + random.nextInt(27); 532 cal.set(year, month, day); 533 timeIntervalEnd = cal.getTime(); 534 535 return new TimeInterval(from, timeIntervalEnd); 536 } 537 }