Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
JobSchedulerBuilder |
|
| 1.8461538461538463;1.846 |
1 | package org.apache.onami.scheduler; | |
2 | ||
3 | /* | |
4 | * Licensed to the Apache Software Foundation (ASF) under one | |
5 | * or more contributor license agreements. See the NOTICE file | |
6 | * distributed with this work for additional information | |
7 | * regarding copyright ownership. The ASF licenses this file | |
8 | * to you under the Apache License, Version 2.0 (the | |
9 | * "License"); you may not use this file except in compliance | |
10 | * with the License. You may obtain a copy of the License at | |
11 | * | |
12 | * http://www.apache.org/licenses/LICENSE-2.0 | |
13 | * | |
14 | * Unless required by applicable law or agreed to in writing, | |
15 | * software distributed under the License is distributed on an | |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
17 | * KIND, either express or implied. See the License for the | |
18 | * specific language governing permissions and limitations | |
19 | * under the License. | |
20 | */ | |
21 | ||
22 | import static java.lang.String.format; | |
23 | import static java.util.TimeZone.getDefault; | |
24 | import static org.apache.onami.scheduler.Scheduled.DEFAULT; | |
25 | import static org.quartz.CronScheduleBuilder.cronSchedule; | |
26 | import static org.quartz.JobBuilder.newJob; | |
27 | import static org.quartz.JobKey.jobKey; | |
28 | import static org.quartz.TriggerBuilder.newTrigger; | |
29 | import static org.quartz.TriggerKey.triggerKey; | |
30 | import static org.quartz.utils.Key.DEFAULT_GROUP; | |
31 | ||
32 | import java.util.TimeZone; | |
33 | ||
34 | import javax.inject.Inject; | |
35 | ||
36 | import org.quartz.Job; | |
37 | import org.quartz.JobKey; | |
38 | import org.quartz.Scheduler; | |
39 | import org.quartz.Trigger; | |
40 | import org.quartz.TriggerKey; | |
41 | ||
42 | import com.google.inject.ProvisionException; | |
43 | ||
44 | /** | |
45 | * DSL to produce {@code Job} and add to a {@code Scheduler}, | |
46 | * and associate the related {@code Trigger} with it. | |
47 | */ | |
48 | public final class JobSchedulerBuilder { | |
49 | ||
50 | /** | |
51 | * The type of the {@code Job} to be executed. | |
52 | */ | |
53 | private final Class<? extends Job> jobClass; | |
54 | ||
55 | /** | |
56 | * The {@code Job} name, must be unique within the group. | |
57 | */ | |
58 | 5 | private String jobName = DEFAULT; |
59 | ||
60 | /** | |
61 | * The {@code Job} group name. | |
62 | */ | |
63 | 5 | private String jobGroup = DEFAULT_GROUP; |
64 | ||
65 | /** | |
66 | * Instructs the {@code Scheduler} whether or not the {@code Job} should | |
67 | * be re-executed if a {@code recovery} or {@code fail-over} situation is | |
68 | * encountered. | |
69 | */ | |
70 | 5 | private boolean requestRecovery = false; |
71 | ||
72 | /** | |
73 | * Whether or not the {@code Job} should remain stored after it is | |
74 | * orphaned (no {@code Trigger}s point to it). | |
75 | */ | |
76 | 5 | private boolean storeDurably = false; |
77 | ||
78 | /** | |
79 | * The {@code Trigger} name, must be unique within the group. | |
80 | */ | |
81 | 5 | private String triggerName = DEFAULT; |
82 | ||
83 | /** | |
84 | * The {@code Trigger} group. | |
85 | */ | |
86 | 5 | private String triggerGroup = DEFAULT_GROUP; |
87 | ||
88 | /** | |
89 | * The cron expression to base the schedule on. | |
90 | */ | |
91 | private String cronExpression; | |
92 | ||
93 | /** | |
94 | * The time zone for which the {@code cronExpression} | |
95 | * of this {@code CronTrigger} will be resolved. | |
96 | */ | |
97 | 5 | private TimeZone timeZone = getDefault(); |
98 | ||
99 | /** | |
100 | * The {@code Trigger}'s priority. When more than one {@code Trigger} have the same | |
101 | * fire time, the scheduler will fire the one with the highest priority | |
102 | * first. | |
103 | */ | |
104 | 5 | private int priority = 0; |
105 | ||
106 | /** | |
107 | * The {@code Trigger} to be used to schedule the {@code Job} | |
108 | * | |
109 | * @since 1.2 | |
110 | */ | |
111 | private Trigger trigger; | |
112 | ||
113 | /** | |
114 | * Indicates whether the job's trigger should be updated if it is already existing when being | |
115 | * scheduled (which is typically the case with a persistent {@link org.quartz.spi.JobStore}. | |
116 | * | |
117 | * @since 1.3 | |
118 | */ | |
119 | 5 | private boolean updateExistingTrigger = false; |
120 | ||
121 | /** | |
122 | * Creates a new {@code JobSchedulerBuilder} instance. | |
123 | * | |
124 | * This class can't be instantiated by users. | |
125 | * | |
126 | * @param jobClass The type of the {@code Job} to be executed | |
127 | */ | |
128 | JobSchedulerBuilder( final Class<? extends Job> jobClass ) | |
129 | 5 | { |
130 | 5 | this.jobClass = jobClass; |
131 | 5 | } |
132 | ||
133 | /** | |
134 | * Sets the {@code Job} name, must be unique within the group. | |
135 | * | |
136 | * @param jobName The {@code Job} name, must be unique within the group | |
137 | * @return This builder instance | |
138 | */ | |
139 | public JobSchedulerBuilder withJobName( String jobName ) | |
140 | { | |
141 | 4 | this.jobName = jobName; |
142 | 4 | return this; |
143 | } | |
144 | ||
145 | /** | |
146 | * Sets the {@code Job} group. | |
147 | * | |
148 | * @param jobGroup The {@code Job} group | |
149 | * @return This builder instance | |
150 | */ | |
151 | public JobSchedulerBuilder withJobGroup( String jobGroup ) | |
152 | { | |
153 | 4 | this.jobGroup = jobGroup; |
154 | 4 | return this; |
155 | } | |
156 | ||
157 | /** | |
158 | * Instructs the {@code Scheduler} whether or not the {@code Job} should | |
159 | * be re-executed if a {@code recovery} or {@code fail-over} situation is | |
160 | * encountered. | |
161 | * | |
162 | * @param requestRecovery The activation flag | |
163 | * @return This builder instance | |
164 | */ | |
165 | public JobSchedulerBuilder withRequestRecovery( boolean requestRecovery ) | |
166 | { | |
167 | 4 | this.requestRecovery = requestRecovery; |
168 | 4 | return this; |
169 | } | |
170 | ||
171 | /** | |
172 | * Whether or not the {@code Job} should remain stored after it is | |
173 | * orphaned (no {@code Trigger}s point to it). | |
174 | * | |
175 | * @param storeDurably The activation flag | |
176 | * @return This builder instance | |
177 | */ | |
178 | public JobSchedulerBuilder withStoreDurably( boolean storeDurably ) | |
179 | { | |
180 | 4 | this.storeDurably = storeDurably; |
181 | 4 | return this; |
182 | } | |
183 | ||
184 | /** | |
185 | * Sets the {@code Trigger} name, must be unique within the group. | |
186 | * | |
187 | * @param triggerName The {@code Trigger} name, must be unique within the group | |
188 | * @return This builder instance | |
189 | */ | |
190 | public JobSchedulerBuilder withTriggerName( String triggerName ) | |
191 | { | |
192 | 4 | this.triggerName = triggerName; |
193 | 4 | return this; |
194 | } | |
195 | ||
196 | /** | |
197 | * Sets the {@code Trigger} group. | |
198 | * | |
199 | * @param triggerGroup The {@code Trigger} group | |
200 | * @return This builder instance | |
201 | */ | |
202 | public JobSchedulerBuilder withTriggerGroup( String triggerGroup ) | |
203 | { | |
204 | 0 | this.triggerGroup = triggerGroup; |
205 | 0 | return this; |
206 | } | |
207 | ||
208 | /** | |
209 | * Sets the cron expression to base the schedule on. | |
210 | * | |
211 | * @param cronExpression The cron expression to base the schedule on | |
212 | * @return This builder instance | |
213 | */ | |
214 | public JobSchedulerBuilder withCronExpression( String cronExpression ) | |
215 | { | |
216 | 4 | this.cronExpression = cronExpression; |
217 | 4 | return this; |
218 | } | |
219 | ||
220 | /** | |
221 | * Sets the time zone for which the {@code cronExpression} of this | |
222 | * {@code CronTrigger} will be resolved. | |
223 | * | |
224 | * @param timeZone The time zone for which the {@code cronExpression} | |
225 | * of this {@code CronTrigger} will be resolved. | |
226 | * @return This builder instance | |
227 | */ | |
228 | public JobSchedulerBuilder withTimeZone( TimeZone timeZone ) | |
229 | { | |
230 | 0 | this.timeZone = timeZone; |
231 | 0 | return this; |
232 | } | |
233 | ||
234 | /** | |
235 | * Sets the {@code Trigger}'s priority. When more than one {@code Trigger} have the same | |
236 | * fire time, the scheduler will fire the one with the highest priority | |
237 | * first. | |
238 | * | |
239 | * @param priority The {@code Trigger}'s priority | |
240 | * @return This builder instance | |
241 | */ | |
242 | public JobSchedulerBuilder withPriority( int priority ) | |
243 | { | |
244 | 0 | this.priority = priority; |
245 | 0 | return this; |
246 | } | |
247 | ||
248 | /** | |
249 | * Sets the {@code Trigger} that will be used to schedule | |
250 | * the {@code Job}. | |
251 | * | |
252 | * <p> | |
253 | * Be aware that using using this method will override any other | |
254 | * {@code Trigger}-related operation, like {@link #withTriggerGroup(String)} | |
255 | * or {@link #withTimeZone(TimeZone)} | |
256 | * | |
257 | * @param trigger The {@code Trigger} to associate with the {@code Job} | |
258 | * @return This builder instance | |
259 | * @since 1.2 | |
260 | */ | |
261 | public JobSchedulerBuilder withTrigger(Trigger trigger) | |
262 | { | |
263 | 1 | this.trigger = trigger; |
264 | 1 | return this; |
265 | } | |
266 | ||
267 | /** | |
268 | * Requests an existing trigger (sharing the same key as the new trigger) for this job to | |
269 | * be replaced with the new trigger. | |
270 | * | |
271 | * @return This builder instance | |
272 | * @since 1.3 | |
273 | */ | |
274 | public JobSchedulerBuilder updateExistingTrigger() | |
275 | { | |
276 | 2 | this.updateExistingTrigger = true; |
277 | 2 | return this; |
278 | } | |
279 | ||
280 | /** | |
281 | * Add the produced {@code Job} to the given {@code Scheduler}, | |
282 | * and associate the related {@code Trigger} with it. | |
283 | * | |
284 | * Users <b>MUST NOT</b> use this method! | |
285 | * | |
286 | * @param scheduler The given {@code Scheduler} | |
287 | * @throws Exception If any error occurs | |
288 | */ | |
289 | @Inject | |
290 | public void schedule( Scheduler scheduler ) | |
291 | throws Exception | |
292 | { | |
293 | 5 | if ( cronExpression == null && trigger == null ) |
294 | { | |
295 | 0 | throw new ProvisionException( format( "Impossible to schedule Job '%s' without cron expression", |
296 | jobClass.getName() ) ); | |
297 | } | |
298 | 5 | if ( cronExpression != null && trigger != null ) |
299 | { | |
300 | 0 | throw new ProvisionException( format( "Impossible to schedule Job '%s' with cron expression " + |
301 | "and an associated Trigger at the same time", jobClass.getName() ) ); | |
302 | } | |
303 | ||
304 | 5 | JobKey jobKey = jobKey( DEFAULT.equals( jobName ) ? jobClass.getName() : jobName, jobGroup ); |
305 | 5 | TriggerKey triggerKey = triggerKey( DEFAULT.equals( triggerName ) ? jobClass.getCanonicalName() : triggerName, triggerGroup ); |
306 | ||
307 | 5 | if ( updateExistingTrigger && scheduler.checkExists( triggerKey ) ) { |
308 | 1 | scheduler.unscheduleJob( triggerKey ); |
309 | } | |
310 | ||
311 | 5 | scheduler.scheduleJob( newJob( jobClass ) |
312 | .withIdentity( jobKey ) | |
313 | .requestRecovery( requestRecovery ) | |
314 | .storeDurably( storeDurably ).build(), | |
315 | ( trigger == null ) ? | |
316 | newTrigger() | |
317 | .withIdentity( triggerKey ) | |
318 | .withSchedule( cronSchedule( cronExpression ) | |
319 | .inTimeZone( timeZone ) ) | |
320 | .withPriority( priority ) | |
321 | .build() | |
322 | : trigger); | |
323 | 5 | } |
324 | ||
325 | } |