1616
1717package com .google .appengine .api .taskqueue .dev ;
1818
19+ import static org .quartz .JobBuilder .newJob ;
20+ import static org .quartz .JobKey .jobKey ;
21+ import static org .quartz .TriggerBuilder .newTrigger ;
22+ import static org .quartz .impl .matchers .GroupMatcher .jobGroupEquals ;
23+ import static org .quartz .impl .matchers .GroupMatcher .triggerGroupEquals ;
24+
1925import com .google .appengine .api .taskqueue .dev .QueueStateInfo .TaskStateInfo ;
2026import com .google .appengine .api .taskqueue_bytes .TaskQueuePb .TaskQueueAddRequest ;
2127import com .google .appengine .api .taskqueue_bytes .TaskQueuePb .TaskQueueAddRequest .Header ;
2834import com .google .apphosting .utils .config .QueueXml ;
2935import com .google .common .flogger .GoogleLogger ;
3036import com .google .protobuf .ByteString ;
37+ import java .time .Instant ;
3138import java .util .ArrayList ;
32- import java .util .Arrays ;
3339import java .util .Collections ;
3440import java .util .Date ;
3541import java .util .List ;
42+ import java .util .Set ;
3643import org .quartz .Job ;
44+ import org .quartz .JobDataMap ;
3745import org .quartz .JobDetail ;
3846import org .quartz .JobExecutionContext ;
3947import org .quartz .JobExecutionException ;
48+ import org .quartz .JobKey ;
4049import org .quartz .Scheduler ;
4150import org .quartz .SchedulerException ;
4251import org .quartz .SimpleTrigger ;
4352import org .quartz .Trigger ;
53+ import org .quartz .impl .JobExecutionContextImpl ;
54+ import org .quartz .spi .OperableTrigger ;
4455import org .quartz .spi .TriggerFiredBundle ;
4556
4657/**
@@ -89,7 +100,7 @@ Mode getMode() {
89100 // to the contrary, pausing a job group only pauses jobs that already
90101 // exist. We need to make sure all future jobs are paused, and that
91102 // works if we pause the trigger group.
92- scheduler .pauseTriggerGroup ( getQueueName ());
103+ scheduler .pauseTriggers ( triggerGroupEquals ( getQueueName () ));
93104 } catch (SchedulerException e ) {
94105 throw new ApiProxy .ApplicationException (ErrorCode .INTERNAL_ERROR_VALUE , e .getMessage ());
95106 }
@@ -112,7 +123,7 @@ private synchronized String scheduleTask(TaskQueueAddRequest.Builder addRequest)
112123 taskName = genTaskName ();
113124 }
114125 try {
115- if (scheduler .getJobDetail ( taskName , getQueueName ()) != null ) {
126+ if (scheduler .checkExists ( jobKey ( taskName , getQueueName ())) ) {
116127 throw new ApiProxy .ApplicationException (ErrorCode .TASK_ALREADY_EXISTS_VALUE );
117128 }
118129 } catch (SchedulerException e ) {
@@ -121,19 +132,32 @@ private synchronized String scheduleTask(TaskQueueAddRequest.Builder addRequest)
121132
122133 TaskQueueRetryParameters retryParams = getRetryParameters (addRequest );
123134 long etaMillis = addRequest .getEtaUsec () / 1000L ;
124- SimpleTrigger trigger = new SimpleTrigger (taskName , getQueueName ());
125- trigger .setStartTime (new Date (etaMillis ));
126- JobDetail jd = newUrlFetchJobDetail (taskName , getQueueName (), addRequest , retryParams );
135+
136+ JobDataMap jobDataMap =
137+ newUrlFetchJobDataMap (taskName , getQueueName (), addRequest , retryParams );
138+
139+ JobDetail job =
140+ newJob (UrlFetchJob .class )
141+ .withIdentity (taskName , getQueueName ())
142+ .usingJobData (jobDataMap )
143+ .build ();
144+
145+ Trigger trigger =
146+ newTrigger ()
147+ .withIdentity (taskName , getQueueName ())
148+ .startAt (Date .from (Instant .ofEpochMilli (etaMillis )))
149+ .build ();
150+
127151 try {
128- scheduler .scheduleJob (jd , trigger );
152+ scheduler .scheduleJob (job , trigger );
129153 } catch (SchedulerException e ) {
130154 throw new ApiProxy .ApplicationException (ErrorCode .INTERNAL_ERROR_VALUE , e .getMessage ());
131155 }
132156 return taskName ;
133157 }
134158
135159 // broken out to support testing
136- JobDetail newUrlFetchJobDetail (
160+ JobDataMap newUrlFetchJobDataMap (
137161 String taskName ,
138162 String queueName ,
139163 TaskQueueAddRequest .Builder addRequest ,
@@ -143,18 +167,20 @@ JobDetail newUrlFetchJobDetail(
143167 String host = header .getValue ().toStringUtf8 ();
144168 if (host .startsWith ("localhost:" )) {
145169 return new UrlFetchJobDetail (
146- taskName ,
147- queueName ,
148- addRequest ,
149- "http://" + host ,
150- callback ,
151- queueXmlEntry ,
152- retryParams );
170+ taskName ,
171+ queueName ,
172+ addRequest ,
173+ "http://" + host ,
174+ callback ,
175+ queueXmlEntry ,
176+ retryParams )
177+ .getJobDataMap ();
153178 }
154179 }
155180 }
156181 return new UrlFetchJobDetail (
157- taskName , queueName , addRequest , baseUrl , callback , queueXmlEntry , retryParams );
182+ taskName , queueName , addRequest , baseUrl , callback , queueXmlEntry , retryParams )
183+ .getJobDataMap ();
158184 }
159185
160186 @ Override
@@ -177,8 +203,11 @@ TaskQueueAddResponse add(TaskQueueAddRequest.Builder addRequest) {
177203 }
178204
179205 List <String > getSortedJobNames () throws SchedulerException {
180- String [] jobNames = scheduler .getJobNames (getQueueName ());
181- List <String > jobNameList = Arrays .asList (jobNames );
206+ Set <JobKey > jobKeys = scheduler .getJobKeys (jobGroupEquals (getQueueName ()));
207+ List <String > jobNameList = new ArrayList <>();
208+ for (JobKey jobKey : jobKeys ) {
209+ jobNameList .add (jobKey .getName ());
210+ }
182211 Collections .sort (jobNameList );
183212 return jobNameList ;
184213 }
@@ -191,23 +220,27 @@ QueueStateInfo getStateInfo() {
191220 // Get the names of all jobs belonging to this queue (group).
192221 for (String jobName : getSortedJobNames ()) {
193222 // Now get job details
194- UrlFetchJobDetail jd = ( UrlFetchJobDetail ) scheduler .getJobDetail (jobName , getQueueName ());
195- if (jd == null ) {
223+ JobDetail jobDetail = scheduler .getJobDetail (jobKey ( jobName , getQueueName () ));
224+ if (jobDetail == null ) {
196225 // oops, gone, must have already run
197226 continue ;
198227 }
199- Trigger [] triggers = scheduler .getTriggersOfJob (jobName , getQueueName ());
200- if (triggers .length == 0 ) {
228+
229+ UrlFetchJobDetail jd = new UrlFetchJobDetail (jobDetail .getJobDataMap ());
230+
231+ List <? extends Trigger > triggers =
232+ scheduler .getTriggersOfJob (jobKey (jobName , getQueueName ()));
233+ if (triggers .isEmpty ()) {
201234 // must have run in between the time we fetched the job detail and the time we fetched the
202235 // trigger
203236 continue ;
204237 }
205- if (triggers .length != 1 ) {
238+ if (triggers .size () != 1 ) {
206239 throw new IllegalStateException (
207240 "Multiple triggers for task " + jobName + " in queue " + getQueueName ());
208241 }
209- long execTime = triggers [ 0 ] .getStartTime ().getTime ();
210- taskInfoList .add (new TaskStateInfo (jd .getName (), execTime , jd .getAddRequest (), clock ));
242+ long execTime = triggers . get ( 0 ) .getStartTime ().toInstant (). toEpochMilli ();
243+ taskInfoList .add (new TaskStateInfo (jd .getTaskName (), execTime , jd .getAddRequest (), clock ));
211244 }
212245 } catch (SchedulerException e ) {
213246 throw new ApiProxy .ApplicationException (ErrorCode .INTERNAL_ERROR_VALUE );
@@ -231,7 +264,7 @@ QueueStateInfo getStateInfo() {
231264 @ Override
232265 boolean deleteTask (String taskName ) {
233266 try {
234- return scheduler .deleteJob (taskName , getQueueName ());
267+ return scheduler .deleteJob (jobKey ( taskName , getQueueName () ));
235268 } catch (SchedulerException e ) {
236269 throw new ApiProxy .ApplicationException (ErrorCode .INTERNAL_ERROR_VALUE );
237270 }
@@ -241,20 +274,18 @@ boolean deleteTask(String taskName) {
241274 @ Override
242275 void flush () {
243276 try {
244- for (String name : scheduler .getJobNames (getQueueName ())) {
245- scheduler .deleteJob (name , getQueueName ());
246- }
277+ Set <JobKey > jobKeys = scheduler .getJobKeys (jobGroupEquals (getQueueName ()));
278+ scheduler .deleteJobs (new ArrayList <>(jobKeys ));
247279 } catch (SchedulerException e ) {
248280 throw new ApiProxy .ApplicationException (ErrorCode .INTERNAL_ERROR_VALUE );
249281 }
250282 }
251283
252- private JobExecutionContext getExecutionContext (UrlFetchJobDetail jobDetail ) {
253- Trigger trigger = new SimpleTrigger (jobDetail .getTaskName (), jobDetail .getQueueName ());
254- trigger .setJobDataMap (jobDetail .getJobDataMap ());
284+ private JobExecutionContext getExecutionContext (JobDetail jobDetail , SimpleTrigger trigger ) {
255285 TriggerFiredBundle bundle =
256- new TriggerFiredBundle (jobDetail , trigger , null , false , null , null , null , null );
257- return new JobExecutionContext (scheduler , bundle , null );
286+ new TriggerFiredBundle (
287+ jobDetail , (OperableTrigger ) trigger , null , false , null , null , null , null );
288+ return new JobExecutionContextImpl (scheduler , bundle , null );
258289 }
259290
260291 /**
@@ -269,11 +300,19 @@ boolean runTask(String taskName) {
269300 Job job ;
270301 JobExecutionContext context ;
271302 try {
272- UrlFetchJobDetail jd = ( UrlFetchJobDetail ) scheduler .getJobDetail (taskName , getQueueName ());
303+ JobDetail jd = scheduler .getJobDetail (jobKey ( taskName , getQueueName () ));
273304 if (jd == null ) {
274305 return false ;
275306 }
276- context = getExecutionContext (jd );
307+ // Reconstruct trigger for execution context - just needs to hold data map
308+ SimpleTrigger trigger =
309+ (SimpleTrigger )
310+ newTrigger ()
311+ .withIdentity (taskName , getQueueName ())
312+ .usingJobData (jd .getJobDataMap ())
313+ .build ();
314+
315+ context = getExecutionContext (jd , trigger );
277316 job = (Job ) jd .getJobClass ().newInstance ();
278317 } catch (SchedulerException e ) {
279318 return false ;
0 commit comments