| 1 17 18 21 package org.quartz.impl.jdbcjobstore; 22 23 import java.io.ByteArrayInputStream ; 24 import java.io.ByteArrayOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.NotSerializableException ; 28 import java.io.ObjectInputStream ; 29 import java.io.ObjectOutputStream ; 30 import java.math.BigDecimal ; 31 import java.sql.Blob ; 32 import java.sql.Connection ; 33 import java.sql.PreparedStatement ; 34 import java.sql.ResultSet ; 35 import java.sql.SQLException ; 36 import java.sql.Statement ; 37 import java.util.ArrayList ; 38 import java.util.Date ; 39 import java.util.HashMap ; 40 import java.util.HashSet ; 41 import java.util.Iterator ; 42 import java.util.LinkedList ; 43 import java.util.List ; 44 import java.util.Map ; 45 import java.util.Properties ; 46 import java.util.Set ; 47 import java.util.TimeZone ; 48 49 import org.apache.commons.logging.Log; 50 import org.quartz.Calendar; 51 import org.quartz.CronTrigger; 52 import org.quartz.JobDataMap; 53 import org.quartz.JobDetail; 54 import org.quartz.Scheduler; 55 import org.quartz.SimpleTrigger; 56 import org.quartz.Trigger; 57 import org.quartz.spi.ClassLoadHelper; 58 import org.quartz.utils.Key; 59 import org.quartz.utils.TriggerStatus; 60 61 72 public class StdJDBCDelegate implements DriverDelegate, StdJDBCConstants { 73 74 81 82 protected Log logger = null; 83 84 protected String tablePrefix = DEFAULT_TABLE_PREFIX; 85 86 protected String instanceId; 87 88 protected boolean useProperties; 89 90 97 98 108 public StdJDBCDelegate(Log logger, String tablePrefix, String instanceId) { 109 this.logger = logger; 110 this.tablePrefix = tablePrefix; 111 this.instanceId = instanceId; 112 } 113 114 124 public StdJDBCDelegate(Log logger, String tablePrefix, String instanceId, 125 Boolean useProperties) { 126 this.logger = logger; 127 this.tablePrefix = tablePrefix; 128 this.instanceId = instanceId; 129 this.useProperties = useProperties.booleanValue(); 130 } 131 132 139 140 protected boolean canUseProperties() { 141 return useProperties; 142 } 143 144 148 163 public int updateTriggerStatesFromOtherStates(Connection conn, 164 String newState, String oldState1, String oldState2) 165 throws SQLException { 166 PreparedStatement ps = null; 167 168 try { 169 ps = conn 170 .prepareStatement(rtp(UPDATE_TRIGGER_STATES_FROM_OTHER_STATES)); 171 ps.setString(1, newState); 172 ps.setString(2, oldState1); 173 ps.setString(3, oldState2); 174 return ps.executeUpdate(); 175 } finally { 176 closeStatement(ps); 177 } 178 } 179 180 190 public Key[] selectMisfiredTriggers(Connection conn, long ts) 191 throws SQLException { 192 PreparedStatement ps = null; 193 ResultSet rs = null; 194 195 try { 196 ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS)); 197 ps.setBigDecimal(1, new BigDecimal (String.valueOf(ts))); 198 rs = ps.executeQuery(); 199 200 ArrayList list = new ArrayList (); 201 while (rs.next()) { 202 String triggerName = rs.getString(COL_TRIGGER_NAME); 203 String groupName = rs.getString(COL_TRIGGER_GROUP); 204 list.add(new Key(triggerName, groupName)); 205 } 206 Object [] oArr = list.toArray(); 207 Key[] kArr = new Key[oArr.length]; 208 System.arraycopy(oArr, 0, kArr, 0, oArr.length); 209 return kArr; 210 } finally { 211 closeResultSet(rs); 212 closeStatement(ps); 213 } 214 } 215 216 227 public Key[] selectTriggersInState(Connection conn, String state) 228 throws SQLException { 229 PreparedStatement ps = null; 230 ResultSet rs = null; 231 232 try { 233 ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_STATE)); 234 ps.setString(1, state); 235 rs = ps.executeQuery(); 236 237 ArrayList list = new ArrayList (); 238 while (rs.next()) { 239 list.add(new Key(rs.getString(1), rs.getString(2))); 240 } 241 242 Key[] sArr = (Key[]) list.toArray(new Key[list.size()]); 243 return sArr; 244 } finally { 245 closeResultSet(rs); 246 closeStatement(ps); 247 } 248 } 249 250 public Key[] selectMisfiredTriggersInState(Connection conn, String state, 251 long ts) throws SQLException { 252 PreparedStatement ps = null; 253 ResultSet rs = null; 254 255 try { 256 ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_STATE)); 257 ps.setBigDecimal(1, new BigDecimal (String.valueOf(ts))); 258 ps.setString(2, state); 259 rs = ps.executeQuery(); 260 261 ArrayList list = new ArrayList (); 262 while (rs.next()) { 263 String triggerName = rs.getString(COL_TRIGGER_NAME); 264 String groupName = rs.getString(COL_TRIGGER_GROUP); 265 list.add(new Key(triggerName, groupName)); 266 } 267 Object [] oArr = list.toArray(); 268 Key[] kArr = new Key[oArr.length]; 269 System.arraycopy(oArr, 0, kArr, 0, oArr.length); 270 return kArr; 271 } finally { 272 closeResultSet(rs); 273 closeStatement(ps); 274 } 275 } 276 277 292 public boolean selectMisfiredTriggersInStates(Connection conn, String state1, String state2, 293 long ts, int count, List resultList) throws SQLException { 294 PreparedStatement ps = null; 295 ResultSet rs = null; 296 297 try { 298 ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_STATES)); 299 ps.setBigDecimal(1, new BigDecimal (String.valueOf(ts))); 300 ps.setString(2, state1); 301 ps.setString(3, state2); 302 rs = ps.executeQuery(); 303 304 boolean hasReachedLimit = false; 305 while (rs.next() && (hasReachedLimit == false)) { 306 if (resultList.size() == count) { 307 hasReachedLimit = true; 308 } else { 309 String triggerName = rs.getString(COL_TRIGGER_NAME); 310 String groupName = rs.getString(COL_TRIGGER_GROUP); 311 resultList.add(new Key(triggerName, groupName)); 312 } 313 } 314 315 return hasReachedLimit; 316 } finally { 317 closeResultSet(rs); 318 closeStatement(ps); 319 } 320 } 321 322 330 public int countMisfiredTriggersInStates( 331 Connection conn, String state1, String state2, long ts) throws SQLException { 332 PreparedStatement ps = null; 333 ResultSet rs = null; 334 335 try { 336 ps = conn.prepareStatement(rtp(COUNT_MISFIRED_TRIGGERS_IN_STATES)); 337 ps.setBigDecimal(1, new BigDecimal (String.valueOf(ts))); 338 ps.setString(2, state1); 339 ps.setString(3, state2); 340 rs = ps.executeQuery(); 341 342 if (rs.next()) { 343 return rs.getInt(1); 344 } 345 346 throw new SQLException ("No misfired trigger count returned."); 347 } finally { 348 closeResultSet(rs); 349 closeStatement(ps); 350 } 351 } 352 353 364 public Key[] selectMisfiredTriggersInGroupInState(Connection conn, 365 String groupName, String state, long ts) throws SQLException { 366 PreparedStatement ps = null; 367 ResultSet rs = null; 368 369 try { 370 ps = conn 371 .prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE)); 372 ps.setBigDecimal(1, new BigDecimal (String.valueOf(ts))); 373 ps.setString(2, groupName); 374 ps.setString(3, state); 375 rs = ps.executeQuery(); 376 377 ArrayList list = new ArrayList (); 378 while (rs.next()) { 379 String triggerName = rs.getString(COL_TRIGGER_NAME); 380 list.add(new Key(triggerName, groupName)); 381 } 382 Object [] oArr = list.toArray(); 383 Key[] kArr = new Key[oArr.length]; 384 System.arraycopy(oArr, 0, kArr, 0, oArr.length); 385 return kArr; 386 } finally { 387 closeResultSet(rs); 388 closeStatement(ps); 389 } 390 } 391 392 413 public Trigger[] selectTriggersForRecoveringJobs(Connection conn) 414 throws SQLException , IOException , ClassNotFoundException { 415 PreparedStatement ps = null; 416 ResultSet rs = null; 417 418 try { 419 ps = conn 420 .prepareStatement(rtp(SELECT_INSTANCES_RECOVERABLE_FIRED_TRIGGERS)); 421 ps.setString(1, instanceId); 422 setBoolean(ps, 2, true); 423 rs = ps.executeQuery(); 424 425 long dumId = System.currentTimeMillis(); 426 ArrayList list = new ArrayList (); 427 while (rs.next()) { 428 String jobName = rs.getString(COL_JOB_NAME); 429 String jobGroup = rs.getString(COL_JOB_GROUP); 430 String trigName = rs.getString(COL_TRIGGER_NAME); 431 String trigGroup = rs.getString(COL_TRIGGER_GROUP); 432 long firedTime = rs.getLong(COL_FIRED_TIME); 433 int priority = rs.getInt(COL_PRIORITY); 434 SimpleTrigger rcvryTrig = new SimpleTrigger("recover_" 435 + instanceId + "_" + String.valueOf(dumId++), 436 Scheduler.DEFAULT_RECOVERY_GROUP, new Date (firedTime)); 437 rcvryTrig.setJobName(jobName); 438 rcvryTrig.setJobGroup(jobGroup); 439 rcvryTrig.setPriority(priority); 440 rcvryTrig 441 .setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW); 442 443 JobDataMap jd = selectTriggerJobDataMap(conn, trigName, trigGroup); 444 jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_NAME, trigName); 445 jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_GROUP, trigGroup); 446 jd.put(Scheduler.FAILED_JOB_ORIGINAL_TRIGGER_FIRETIME_IN_MILLISECONDS, String.valueOf(firedTime)); 447 rcvryTrig.setJobDataMap(jd); 448 449 list.add(rcvryTrig); 450 } 451 Object [] oArr = list.toArray(); 452 Trigger[] tArr = new Trigger[oArr.length]; 453 System.arraycopy(oArr, 0, tArr, 0, oArr.length); 454 return tArr; 455 } finally { 456 closeResultSet(rs); 457 closeStatement(ps); 458 } 459 } 460 461 470 public int deleteFiredTriggers(Connection conn) throws SQLException { 471 PreparedStatement ps = null; 472 473 try { 474 ps = conn.prepareStatement(rtp(DELETE_FIRED_TRIGGERS)); 475 476 return ps.executeUpdate(); 477 } finally { 478 closeStatement(ps); 479 } 480 } 481 482 public int deleteFiredTriggers(Connection conn, String instanceId) 483 throws SQLException { 484 PreparedStatement ps = null; 485 486 try { 487 ps = conn.prepareStatement(rtp(DELETE_INSTANCES_FIRED_TRIGGERS)); 488 ps.setString(1, instanceId); 489 490 return ps.executeUpdate(); 491 } finally { 492 closeStatement(ps); 493 } 494 } 495 496 500 513 public int insertJobDetail(Connection conn, JobDetail job) 514 throws IOException , SQLException { 515 ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); 516 517 PreparedStatement ps = null; 518 519 int insertResult = 0; 520 521 try { 522 ps = conn.prepareStatement(rtp(INSERT_JOB_DETAIL)); 523 ps.setString(1, job.getName()); 524 ps.setString(2, job.getGroup()); 525 ps.setString(3, job.getDescription()); 526 ps.setString(4, job.getJobClass().getName()); 527 setBoolean(ps, 5, job.isDurable()); 528 setBoolean(ps, 6, job.isVolatile()); 529 setBoolean(ps, 7, job.isStateful()); 530 setBoolean(ps, 8, job.requestsRecovery()); 531 setBytes(ps, 9, baos); 532 533 insertResult = ps.executeUpdate(); 534 } finally { 535 closeStatement(ps); 536 } 537 538 if (insertResult > 0) { 539 String [] jobListeners = job.getJobListenerNames(); 540 for (int i = 0; jobListeners != null && i < jobListeners.length; i++) { 541 insertJobListener(conn, job, jobListeners[i]); 542 } 543 } 544 545 return insertResult; 546 } 547 548 561 public int updateJobDetail(Connection conn, JobDetail job) 562 throws IOException , SQLException { 563 ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); 564 565 PreparedStatement ps = null; 566 567 int insertResult = 0; 568 569 try { 570 ps = conn.prepareStatement(rtp(UPDATE_JOB_DETAIL)); 571 ps.setString(1, job.getDescription()); 572 ps.setString(2, job.getJobClass().getName()); 573 setBoolean(ps, 3, job.isDurable()); 574 setBoolean(ps, 4, job.isVolatile()); 575 setBoolean(ps, 5, job.isStateful()); 576 setBoolean(ps, 6, job.requestsRecovery()); 577 setBytes(ps, 7, baos); 578 ps.setString(8, job.getName()); 579 ps.setString(9, job.getGroup()); 580 581 insertResult = ps.executeUpdate(); 582 } finally { 583 closeStatement(ps); 584 } 585 586 if (insertResult > 0) { 587 deleteJobListeners(conn, job.getName(), job.getGroup()); 588 589 String [] jobListeners = job.getJobListenerNames(); 590 for (int i = 0; jobListeners != null && i < jobListeners.length; i++) { 591 insertJobListener(conn, job, jobListeners[i]); 592 } 593 } 594 595 return insertResult; 596 } 597 598 612 public Key[] selectTriggerNamesForJob(Connection conn, String jobName, 613 String groupName) throws SQLException { 614 PreparedStatement ps = null; 615 ResultSet rs = null; 616 617 try { 618 ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB)); 619 ps.setString(1, jobName); 620 ps.setString(2, groupName); 621 rs = ps.executeQuery(); 622 623 ArrayList list = new ArrayList (10); 624 while (rs.next()) { 625 String trigName = rs.getString(COL_TRIGGER_NAME); 626 String trigGroup = rs.getString(COL_TRIGGER_GROUP); 627 list.add(new Key(trigName, trigGroup)); 628 } 629 Object [] oArr = list.toArray(); 630 Key[] kArr = new Key[oArr.length]; 631 System.arraycopy(oArr, 0, kArr, 0, oArr.length); 632 return kArr; 633 } finally { 634 closeResultSet(rs); 635 closeStatement(ps); 636 } 637 } 638 639 652 public int deleteJobListeners(Connection conn, String jobName, 653 String groupName) throws SQLException { 654 PreparedStatement ps = null; 655 656 try { 657 ps = conn.prepareStatement(rtp(DELETE_JOB_LISTENERS)); 658 ps.setString(1, jobName); 659 ps.setString(2, groupName); 660 return ps.executeUpdate(); 661 } finally { 662 closeStatement(ps); 663 } 664 } 665 666 679 public int deleteJobDetail(Connection conn, String jobName, String groupName) 680 throws SQLException { 681 PreparedStatement ps = null; 682 683 try { 684 if (logger.isDebugEnabled()) { 685 logger.debug("Deleting job: " + groupName + "." + jobName); 686 } 687 ps = conn.prepareStatement(rtp(DELETE_JOB_DETAIL)); 688 ps.setString(1, jobName); 689 ps.setString(2, groupName); 690 return ps.executeUpdate(); 691 } finally { 692 closeStatement(ps); 693 } 694 } 695 696 709 public boolean isJobStateful(Connection conn, String jobName, 710 String groupName) throws SQLException { 711 PreparedStatement ps = null; 712 ResultSet rs = null; 713 714 try { 715 ps = conn.prepareStatement(rtp(SELECT_JOB_STATEFUL)); 716 ps.setString(1, jobName); 717 ps.setString(2, groupName); 718 rs = ps.executeQuery(); 719 if (!rs.next()) { return false; } 720 return getBoolean(rs, COL_IS_STATEFUL); 721 } finally { 722 closeResultSet(rs); 723 closeStatement(ps); 724 } 725 } 726 727 740 public boolean jobExists(Connection conn, String jobName, String groupName) 741 throws SQLException { 742 PreparedStatement ps = null; 743 ResultSet rs = null; 744 745 try { 746 ps = conn.prepareStatement(rtp(SELECT_JOB_EXISTENCE)); 747 ps.setString(1, jobName); 748 ps.setString(2, groupName); 749 rs = ps.executeQuery(); 750 if (rs.next()) { 751 return true; 752 } else { 753 return false; 754 } 755 } finally { 756 closeResultSet(rs); 757 closeStatement(ps); 758 } 759 760 } 761 762 773 public int updateJobData(Connection conn, JobDetail job) 774 throws IOException , SQLException { 775 ByteArrayOutputStream baos = serializeJobData(job.getJobDataMap()); 776 777 PreparedStatement ps = null; 778 779 try { 780 ps = conn.prepareStatement(rtp(UPDATE_JOB_DATA)); 781 setBytes(ps, 1, baos); 782 ps.setString(2, job.getName()); 783 ps.setString(3, job.getGroup()); 784 785 return ps.executeUpdate(); 786 } finally { 787 closeStatement(ps); 788 } 789 } 790 791 |