/** * Produce the <code>Trigger</code>. * * @return a Trigger that meets the specifications of the builder. */ @SuppressWarnings("unchecked") public T build() { if(scheduleBuilder == null) scheduleBuilder = SimpleScheduleBuilder.simpleSchedule(); MutableTrigger trig = scheduleBuilder.build(); trig.setCalendarName(calendarName); trig.setDescription(description); trig.setStartTime(startTime); trig.setEndTime(endTime); if(key == null) key = new TriggerKey(Key.createUniqueName(null), null); trig.setKey(key); if(jobKey != null) trig.setJobKey(jobKey); trig.setPriority(priority); if(!jobDataMap.isEmpty()) trig.setJobDataMap(jobDataMap); return (T) trig; }
/** * Produce the <code>JobDetail</code> instance defined by this * <code>JobBuilder</code>. * * @return the defined JobDetail. */ public JobDetail build() { JobDetailImpl job = new JobDetailImpl(); job.setJobClass(jobClass); job.setDescription(description); if(key == null) key = new JobKey(Key.createUniqueName(null), null); job.setKey(key); job.setDurability(durability); job.setRequestsRecovery(shouldRecover); if(!jobDataMap.isEmpty()) job.setJobDataMap(jobDataMap); return job; }
protected boolean removeJob(Connection conn, SchedulingContext ctxt, String jobName, String groupName, boolean activeDeleteSafe) throws JobPersistenceException { try { Key[] jobTriggers = getDelegate().selectTriggerNamesForJob(conn, jobName, groupName); for (int i = 0; i < jobTriggers.length; ++i) { deleteTriggerAndChildren( conn, jobTriggers[i].getName(), jobTriggers[i].getGroup()); } return deleteJobAndChildren(conn, ctxt, jobName, groupName); } catch (SQLException e) { throw new JobPersistenceException("Couldn't remove job: " + e.getMessage(), e); } }
/** * <p> * Get the names of all of the triggers that have misfired. * </p> * * @param conn * the DB Connection * @return an array of <code>{@link * org.quartz.utils.Key}</code> objects */ public Key[] selectMisfiredTriggers(Connection conn, long ts) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS)); ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); list.add(new Key(triggerName, groupName)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * <p> * Select all of the triggers in a given state. * </p> * * @param conn * the DB Connection * @param state * the state the triggers must be in * @return an array of trigger <code>Key</code> s */ public Key[] selectTriggersInState(Connection conn, String state) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_IN_STATE)); ps.setString(1, state); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { list.add(new Key(rs.getString(1), rs.getString(2))); } Key[] sArr = (Key[]) list.toArray(new Key[list.size()]); return sArr; } finally { closeResultSet(rs); closeStatement(ps); } }
public Key[] selectMisfiredTriggersInState(Connection conn, String state, long ts) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_STATE)); ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); ps.setString(2, state); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); list.add(new Key(triggerName, groupName)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
public List selectStatefulJobsOfTriggerGroup(Connection conn, String groupName) throws SQLException { ArrayList jobList = new ArrayList(); PreparedStatement ps = null; ResultSet rs = null; try { ps = conn .prepareStatement(rtp(SELECT_STATEFUL_JOBS_OF_TRIGGER_GROUP)); ps.setString(1, groupName); setBoolean(ps, 2, true); rs = ps.executeQuery(); while (rs.next()) { jobList.add(new Key(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } } finally { closeResultSet(rs); closeStatement(ps); } return jobList; }
/** * <p> * Select the trigger that will be fired at the given fire time. * </p> * * @param conn * the DB Connection * @param fireTime * the time that the trigger will be fired * @return a <code>{@link org.quartz.utils.Key}</code> representing the * trigger that will be fired at the given fire time, or null if no * trigger will be fired at that time */ public Key selectTriggerForFireTime(Connection conn, long fireTime) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGER_FOR_FIRE_TIME)); ps.setString(1, STATE_WAITING); ps.setBigDecimal(2, new BigDecimal(String.valueOf(fireTime))); rs = ps.executeQuery(); if (rs.next()) { return new Key(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP)); } else { return null; } } finally { closeResultSet(rs); closeStatement(ps); } }
public Key[] selectVolatileTriggers(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_VOLATILE_TRIGGERS)); setBoolean(ps, 1, true); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); list.add(new Key(triggerName, groupName)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
public Key[] selectVolatileJobs(Connection conn) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_VOLATILE_JOBS)); setBoolean(ps, 1, true); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { String triggerName = rs.getString(COL_JOB_NAME); String groupName = rs.getString(COL_JOB_GROUP); list.add(new Key(triggerName, groupName)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { Key sj = (Key) chainLinks.get(context.getJobDetail().getKey()); if(sj == null) { return; } getLog().info("Job '" + context.getJobDetail().getFullName() + "' will now chain to Job '" + sj + "'"); try { if(context.getJobDetail().isVolatile() || context.getTrigger().isVolatile()) { context.getScheduler().triggerJobWithVolatileTrigger(sj.getName(), sj.getGroup()); } else { context.getScheduler().triggerJob(sj.getName(), sj.getGroup()); } } catch(SchedulerException se) { getLog().error("Error encountered during chaining to Job '" + sj + "'", se); } }
/** * <p> * Removes all volatile data. * </p> * * @throws JobPersistenceException * if jobs could not be recovered */ protected void cleanVolatileTriggerAndJobs(Connection conn) throws JobPersistenceException { try { // find volatile jobs & triggers... Key[] volatileTriggers = getDelegate().selectVolatileTriggers(conn); Key[] volatileJobs = getDelegate().selectVolatileJobs(conn); for (int i = 0; i < volatileTriggers.length; i++) { removeTrigger(conn, null, volatileTriggers[i].getName(), volatileTriggers[i].getGroup()); } getLog().info( "Removed " + volatileTriggers.length + " Volatile Trigger(s)."); for (int i = 0; i < volatileJobs.length; i++) { removeJob(conn, null, volatileJobs[i].getName(), volatileJobs[i].getGroup(), true); } getLog().info( "Removed " + volatileJobs.length + " Volatile Job(s)."); // clean up any fired trigger entries getDelegate().deleteVolatileFiredTriggers(conn); } catch (Exception e) { throw new JobPersistenceException("Couldn't clean volatile data: " + e.getMessage(), e); } }
/** * <p> * Get the names of all of the triggers in the given states that have * misfired - according to the given timestamp. No more than count will * be returned. * </p> * * @param conn The DB Connection * @param count The most misfired triggers to return, negative for all * @param resultList Output parameter. A List of * <code>{@link org.quartz.utils.Key}</code> objects. Must not be null. * * @return Whether there are more misfired triggers left to find beyond * the given count. */ public boolean selectMisfiredTriggersInStates(Connection conn, String state1, String state2, long ts, int count, List resultList) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_STATES)); ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); ps.setString(2, state1); ps.setString(3, state2); rs = ps.executeQuery(); boolean hasReachedLimit = false; while (rs.next() && (hasReachedLimit == false)) { if (resultList.size() == count) { hasReachedLimit = true; } else { String triggerName = rs.getString(COL_TRIGGER_NAME); String groupName = rs.getString(COL_TRIGGER_GROUP); resultList.add(new Key(triggerName, groupName)); } } return hasReachedLimit; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * <p> * Get the names of all of the triggers in the given group and state that * have misfired. * </p> * * @param conn * the DB Connection * @return an array of <code>{@link * org.quartz.utils.Key}</code> objects */ public Key[] selectMisfiredTriggersInGroupInState(Connection conn, String groupName, String state, long ts) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn .prepareStatement(rtp(SELECT_MISFIRED_TRIGGERS_IN_GROUP_IN_STATE)); ps.setBigDecimal(1, new BigDecimal(String.valueOf(ts))); ps.setString(2, groupName); ps.setString(3, state); rs = ps.executeQuery(); ArrayList list = new ArrayList(); while (rs.next()) { String triggerName = rs.getString(COL_TRIGGER_NAME); list.add(new Key(triggerName, groupName)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * <p> * Get the names of all of the triggers associated with the given job. * </p> * * @param conn * the DB Connection * @param jobName * the name of the job * @param groupName * the group containing the job * @return an array of <code>{@link * org.quartz.utils.Key}</code> objects */ public Key[] selectTriggerNamesForJob(Connection conn, String jobName, String groupName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(rtp(SELECT_TRIGGERS_FOR_JOB)); ps.setString(1, jobName); ps.setString(2, groupName); rs = ps.executeQuery(); ArrayList list = new ArrayList(10); while (rs.next()) { String trigName = rs.getString(COL_TRIGGER_NAME); String trigGroup = rs.getString(COL_TRIGGER_GROUP); list.add(new Key(trigName, trigGroup)); } Object[] oArr = list.toArray(); Key[] kArr = new Key[oArr.length]; System.arraycopy(oArr, 0, kArr, 0, oArr.length); return kArr; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * <p> * Select the next trigger which will fire to fire between the two given timestamps * in ascending order of fire time, and then descending by priority. * </p> * * @param conn * the DB Connection * @param noLaterThan * highest value of <code>getNextFireTime()</code> of the triggers (exclusive) * @param noEarlierThan * highest value of <code>getNextFireTime()</code> of the triggers (inclusive) * * @return A (never null, possibly empty) list of the identifiers (Key objects) of the next triggers to be fired. */ public List selectTriggerToAcquire(Connection conn, long noLaterThan, long noEarlierThan) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; List nextTriggers = new LinkedList(); try { ps = conn.prepareStatement(rtp(SELECT_NEXT_TRIGGER_TO_ACQUIRE)); // Try to give jdbc driver a hint to hopefully not pull over // more than the few rows we actually need. ps.setFetchSize(5); ps.setMaxRows(5); ps.setString(1, STATE_WAITING); ps.setBigDecimal(2, new BigDecimal(String.valueOf(noLaterThan))); ps.setBigDecimal(3, new BigDecimal(String.valueOf(noEarlierThan))); rs = ps.executeQuery(); while (rs.next() && nextTriggers.size() < 5) { nextTriggers.add(new Key( rs.getString(COL_TRIGGER_NAME), rs.getString(COL_TRIGGER_GROUP))); } return nextTriggers; } finally { closeResultSet(rs); closeStatement(ps); } }
public List selectInstancesFiredTriggerRecords(Connection conn, String instanceName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { List lst = new LinkedList(); ps = conn.prepareStatement(rtp(SELECT_INSTANCES_FIRED_TRIGGERS)); ps.setString(1, instanceName); rs = ps.executeQuery(); while (rs.next()) { FiredTriggerRecord rec = new FiredTriggerRecord(); rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); rec.setTriggerIsVolatile(getBoolean(rs, COL_IS_VOLATILE)); rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { rec.setJobIsStateful(getBoolean(rs, COL_IS_STATEFUL)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } rec.setPriority(rs.getInt(COL_PRIORITY)); lst.add(rec); } return lst; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * Add a chain mapping - when the Job identified by the first key completes * the job identified by the second key will be triggered. * * @param firstJob a Key with the name and group of the first job * @param secondJob a Key with the name and group of the follow-up job */ public void addJobChainLink(Key firstJob, Key secondJob) { if(firstJob == null || secondJob == null) { throw new IllegalArgumentException("Key cannot be null!"); } if(firstJob.getName() == null || secondJob.getName() == null) { throw new IllegalArgumentException("Key cannot have a null name!"); } chainLinks.put(firstJob, secondJob); }
private void onStoreAfterTrigger(TriggerDefinition cronyxTrigger) throws SchedulerException { if (cronyxTrigger instanceof After) { After afterTrigger = (After) cronyxTrigger; if (afterTrigger.getTriggerKey().getGroup() == null) { afterTrigger.getTriggerKey().setGroup(Key.DEFAULT_GROUP); } validateTriggersExist(afterTrigger.getPreviousTriggers()); List<NameAndGroupOrderedPair> edges = afterDAO.getAllAncestorPairs(afterTrigger.getPreviousTriggers()); afterTrigger.getPreviousTriggers().forEach(k -> edges.add(new NameAndGroupOrderedPair(k, afterTrigger.getTriggerKey()))); graphValidator.validateGraph(edges); afterDAO.storeAfterTrigger(afterTrigger.getPreviousTriggers(), afterTrigger.getTriggerKey()); } }
@Nullable public EntityT execute(final ODatabaseDocumentTx db, final Key key) { checkNotNull(db); checkNotNull(key); List<ODocument> results = db.command(new OSQLSynchQuery<>(query)) .execute(key.getName(), key.getGroup()); if (results.isEmpty()) { return null; } return adapter.readEntity(results.get(0)); }
public boolean execute(final ODatabaseDocumentTx db, final Key key) { checkNotNull(db); checkNotNull(key); int records = db.command(new OCommandSQL(query)) .execute(key.getName(), key.getGroup()); return records == 1; }
public boolean execute(final ODatabaseDocumentTx db, final Key key) { checkNotNull(db); checkNotNull(key); List<ODocument> results = db.command(new OSQLSynchQuery<>(query)) .execute(key.getName(), key.getGroup()); return results.get(0).<Long>field("count") == 1; }
@Override public void activate() throws ApplicationActivationException { scheduledJobs = new HashMap<ServiceExecution, Key>(); serviceExecutionCallback = new ServiceExecutionCallback(); try { quartzScheduler = StdSchedulerFactory.getDefaultScheduler(); quartzScheduler.start(); } catch (SchedulerException e) { log.error("Could not initialize ServiceExecutionScheduler internal scheduler.", e); throw new ApplicationActivationException(e); } }
/** * Create an AndMatcher that depends upon the result of both of the given matchers. */ public static <U extends Key<?>> AndMatcher<U> and(Matcher<U> leftOperand, Matcher<U> rightOperand) { return new AndMatcher<U>(leftOperand, rightOperand); }
/** * Create a NameMatcher that matches names equaling the given string. */ public static <T extends Key<?>> NameMatcher<T> nameEquals(String compareTo) { return new NameMatcher<T>(compareTo, StringOperatorName.EQUALS); }
/** * Create a NameMatcher that matches names starting with the given string. */ public static <U extends Key<?>> NameMatcher<U> nameStartsWith(String compareTo) { return new NameMatcher<U>(compareTo, StringOperatorName.STARTS_WITH); }
/** * Create a NameMatcher that matches names ending with the given string. */ public static <U extends Key<?>> NameMatcher<U> nameEndsWith(String compareTo) { return new NameMatcher<U>(compareTo, StringOperatorName.ENDS_WITH); }
/** * Create a NameMatcher that matches names containing the given string. */ public static <U extends Key<?>> NameMatcher<U> nameContains(String compareTo) { return new NameMatcher<U>(compareTo, StringOperatorName.CONTAINS); }
/** * Create a NotMatcher that reverses the result of the given matcher. */ public static <U extends Key<?>> NotMatcher<U> not(Matcher<U> operand) { return new NotMatcher<U>(operand); }
/** * Create a KeyMatcher that matches Keys that equal the given key. */ public static <U extends Key<?>> KeyMatcher<U> keyEquals(U compareTo) { return new KeyMatcher<U>(compareTo); }
/** * Create a GroupMatcher that matches groups equaling the given string. */ public static <T extends Key<T>> GroupMatcher<T> groupEquals(String compareTo) { return new GroupMatcher<T>(compareTo, StringOperatorName.EQUALS); }
/** * Create a GroupMatcher that matches groups starting with the given string. */ public static <T extends Key<T>> GroupMatcher<T> groupStartsWith(String compareTo) { return new GroupMatcher<T>(compareTo, StringOperatorName.STARTS_WITH); }
/** * Create a GroupMatcher that matches groups ending with the given string. */ public static <T extends Key<T>> GroupMatcher<T> groupEndsWith(String compareTo) { return new GroupMatcher<T>(compareTo, StringOperatorName.ENDS_WITH); }
/** * Create a GroupMatcher that matches groups containing the given string. */ public static <T extends Key<T>> GroupMatcher<T> groupContains(String compareTo) { return new GroupMatcher<T>(compareTo, StringOperatorName.CONTAINS); }
/** * Create a GroupMatcher that matches groups starting with the given string. */ public static <T extends Key<T>> GroupMatcher<T> anyGroup() { return new GroupMatcher<T>("", StringOperatorName.ANYTHING); }
/** * Create an OrMatcher that depends upon the result of at least one of the given matchers. */ public static <U extends Key<?>> OrMatcher<U> or(Matcher<U> leftOperand, Matcher<U> rightOperand) { return new OrMatcher<U>(leftOperand, rightOperand); }
/** * <p> * Select the states of all fired-trigger records for a given trigger, or * trigger group if trigger name is <code>null</code>. * </p> * * @return a List of FiredTriggerRecord objects. */ public List selectFiredTriggerRecords(Connection conn, String triggerName, String groupName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { List lst = new LinkedList(); if (triggerName != null) { ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER)); ps.setString(1, triggerName); ps.setString(2, groupName); } else { ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGER_GROUP)); ps.setString(1, groupName); } rs = ps.executeQuery(); while (rs.next()) { FiredTriggerRecord rec = new FiredTriggerRecord(); rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); rec.setPriority(rs.getInt(COL_PRIORITY)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); rec.setTriggerIsVolatile(getBoolean(rs, COL_IS_VOLATILE)); rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { rec.setJobIsStateful(getBoolean(rs, COL_IS_STATEFUL)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } lst.add(rec); } return lst; } finally { closeResultSet(rs); closeStatement(ps); } }
/** * <p> * Select the states of all fired-trigger records for a given job, or job * group if job name is <code>null</code>. * </p> * * @return a List of FiredTriggerRecord objects. */ public List selectFiredTriggerRecordsByJob(Connection conn, String jobName, String groupName) throws SQLException { PreparedStatement ps = null; ResultSet rs = null; try { List lst = new LinkedList(); if (jobName != null) { ps = conn.prepareStatement(rtp(SELECT_FIRED_TRIGGERS_OF_JOB)); ps.setString(1, jobName); ps.setString(2, groupName); } else { ps = conn .prepareStatement(rtp(SELECT_FIRED_TRIGGERS_OF_JOB_GROUP)); ps.setString(1, groupName); } rs = ps.executeQuery(); while (rs.next()) { FiredTriggerRecord rec = new FiredTriggerRecord(); rec.setFireInstanceId(rs.getString(COL_ENTRY_ID)); rec.setFireInstanceState(rs.getString(COL_ENTRY_STATE)); rec.setFireTimestamp(rs.getLong(COL_FIRED_TIME)); rec.setPriority(rs.getInt(COL_PRIORITY)); rec.setSchedulerInstanceId(rs.getString(COL_INSTANCE_NAME)); rec.setTriggerIsVolatile(getBoolean(rs, COL_IS_VOLATILE)); rec.setTriggerKey(new Key(rs.getString(COL_TRIGGER_NAME), rs .getString(COL_TRIGGER_GROUP))); if (!rec.getFireInstanceState().equals(STATE_ACQUIRED)) { rec.setJobIsStateful(getBoolean(rs, COL_IS_STATEFUL)); rec.setJobRequestsRecovery(rs .getBoolean(COL_REQUESTS_RECOVERY)); rec.setJobKey(new Key(rs.getString(COL_JOB_NAME), rs .getString(COL_JOB_GROUP))); } lst.add(rec); } return lst; } finally { closeResultSet(rs); closeStatement(ps); } }
public Key getJobKey() { return jobKey; }
public Key getTriggerKey() { return triggerKey; }