Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit df83fc3

Browse files
committed
quartz module fix jooby-project#43
A job scheduler from [Quartz](http://quartz-scheduler.org/). ```xml <dependency> <groupId>org.jooby</groupId> <artifactId>jooby-quartz</artifactId> <version>{{version}}</version> </dependency> ``` ```java import org.jooby.quartz.Quartz; { use(new Quartz().with(MyJob.class)); } ``` Previous example will startup Quartz and schedule MyJob. A job can implement the ```Job``` interface as described in the [Quartz documentation] (http://quartz-scheduler.org/documentation) If you prefer to not implement the ```Job``` interface, all you have to do is to annotated a method with the ```Scheduled``` annotation. By default, job name is set the class name or to the method name. Default group is set to the package name of the job class. A job method must follow this rules: * It must be a public method * Without a return value * Have ZERO arguments * or just ONE argument of type ```JobExecutionContext``` The next section will you show how to add a trigger to a job and some examples too. Trigger are defined by the ```Scheduled``` annotation. The annotation defined a single and required attributes, which is basically a trigger expression or a reference to it. Example 1: run every 10s ```java public class MyJob implements Job { @scheduled("10s") public void execute(JobExecutionContext ctx) throws JobExecutionException { ... } } ``` Example 2: run every 10s (no ```Job```) ```java public class MyJob { @scheduled("10s") public void doWork() { ... } } ``` The ```Scheduled``` define a ```Quartz Trigger```. There you can put expressions like: ```5s```, ```15minutes```, ```2hours```, etc... or a CRON expression: ```0/3 * * * * ?```. It is also possible to put the name of property: ```java public class MyJob { @scheduled("job.expr") public void doWork() { ... } } ``` And again the property: ```job.expr``` must be one of the previously described expressions. If you have two or more jobs doing something similar, it is possible to group all them into one single class: ```java public class MyJobs { @scheduled("5minutes") public void job1() { ... } @scheduled("1h") public void job2() { ... } } ``` Not much to add here, just let you know jobs are created by Guice. ```java public class MyJob { private A a; @Inject public MyJob(A a) { this.a = a; } @scheduled("5minutes") public void doWork() { this.a.doWork(); } } ``` Injecting a ```Scheduler``` ```java public class MyJobManager { private Scheduler scheduler; @Inject public MyJobManager(Scheduler scheduler) { this.scheduler = scheduler; } } ``` Example: Setting max number of threads ```properties org.quartz.threadPool.threadCount = 1 # default is number of available processors ``` Configuration follows the [Quartz documentation](http://quartz-scheduler.org/documentation). The only difference is that you need to put add the properties on your ```*.conf``` file, NOT in a custom ```quartz.properties``` file. Jdbc Store is fully supported but it depends on the <code>jooby-jdbc</code> module. So, in order to use the Jdbc Store you need to follow these steps: 1st. Install the Jdbc module: ```java { use(new Jdbc()); use(new Quartz(MyJob.class)); } ``` 2nd. Set the quartz properties: ```properties org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.dataSource = db ``` When ```Scheduled``` isn't not enough and/or if you prefer to build jobs manually, you can try one of the available alternatives. Example 1: build the trigger and use default job naming ```java { use(new Quartz() .with(MyJob.class, trigger {@literal ->} { trigger .withSchedule(withIntervalInDays(3)) .startAt(futureDate(10, MINUTES)); }) ); } ``` Example 2: build the job, the trigger and use default job naming ```java { use(new Quartz() .with(MyJob.class, (job, trigger) {@literal ->} { job.withDescription("etc..."); trigger .withSchedule(withIntervalInDays(3)) .startAt(futureDate(10, MINUTES)); }) ); } ``` Example 3: build and set everything from scratch ```java { use(new Quartz() .with( newJob(MyJob.class).withDescription("etc...") .build(), newTrigger() .withSchedule(withIntervalInDays(3)) .startAt(futureDate(10, MINUTES)) .build() }) ); } ``` That's all folks! Enjoy it!!
1 parent d760a83 commit df83fc3

File tree

48 files changed

+2644
-262
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2644
-262
lines changed

coverage-report/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<source>${project.parent.basedir}/jooby-jetty/src/main/java</source>
4343
<source>${project.parent.basedir}/jooby-netty/src/main/java</source>
4444
<source>${project.parent.basedir}/jooby-servlet/src/main/java</source>
45+
<source>${project.parent.basedir}/jooby-quartz/src/main/java</source>
4546
</sources>
4647
</configuration>
4748
</execution>
@@ -62,6 +63,7 @@
6263
<source>${project.parent.basedir}/jooby-jetty/src/test/java</source>
6364
<source>${project.parent.basedir}/jooby-netty/src/test/java</source>
6465
<source>${project.parent.basedir}/jooby-servlet/src/test/java</source>
66+
<source>${project.parent.basedir}/jooby-quartz/src/test/java</source>
6567
</sources>
6668
</configuration>
6769
</execution>
@@ -179,6 +181,12 @@
179181
<version>${project.version}</version>
180182
</dependency>
181183

184+
<dependency>
185+
<groupId>org.jooby</groupId>
186+
<artifactId>jooby-quartz</artifactId>
187+
<version>${project.version}</version>
188+
</dependency>
189+
182190
<dependency>
183191
<groupId>org.jooby</groupId>
184192
<artifactId>jooby-jackson</artifactId>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.jooby.quartz;
2+
3+
import java.util.UUID;
4+
import java.util.concurrent.CountDownLatch;
5+
6+
import org.jooby.test.ServerFeature;
7+
import org.junit.Test;
8+
import org.quartz.DisallowConcurrentExecution;
9+
10+
import com.typesafe.config.ConfigFactory;
11+
import com.typesafe.config.ConfigValueFactory;
12+
13+
public class QuartzFeature extends ServerFeature {
14+
15+
private static volatile CountDownLatch latch = new CountDownLatch(1);
16+
17+
@DisallowConcurrentExecution
18+
public static class QJob {
19+
20+
@Scheduled("3s")
21+
public void run() {
22+
latch.countDown();
23+
}
24+
}
25+
26+
{
27+
use(ConfigFactory.empty()
28+
.withValue("org.quartz.scheduler.instanceName",
29+
ConfigValueFactory.fromAnyRef(UUID.randomUUID().toString())));
30+
use(new Quartz(QJob.class));
31+
32+
get("/boost", () -> "done");
33+
}
34+
35+
@Test
36+
public void runJob() throws Exception {
37+
latch = new CountDownLatch(1);
38+
request()
39+
.get("/boost")
40+
.expect("done");
41+
latch.await();
42+
}
43+
}

jooby-jdbc/src/main/java/org/jooby/jdbc/Jdbc.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ public void configure(final Env mode, final Config config, final Binder binder)
6767

6868
binder.bind(dataSourceKey(DataSource.class))
6969
.toProvider(ds).asEagerSingleton();
70+
if (DEFAULT_DB.equals(dbName)) {
71+
// bind with db name too
72+
binder.bind(Key.get(DataSource.class, Names.named(dbName))).toProvider(ds);
73+
}
7074
}
7175

7276
@Override

jooby-jdbc/src/test/java/org/jooby/jdbc/JdbcTest.java

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ public void memdb() throws Exception {
4848

4949
Capture<Provider<DataSource>> provider = new Capture<>();
5050
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
51-
expect(binding.toProvider(capture(provider))).andReturn(scope);
51+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
5252
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
53+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
5354

5455
Object[] mocks = {binder, binding, scope };
5556

@@ -96,8 +97,9 @@ public void fsdb() throws Exception {
9697

9798
Capture<Provider<DataSource>> provider = new Capture<>();
9899
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
99-
expect(binding.toProvider(capture(provider))).andReturn(scope);
100+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
100101
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
102+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
101103

102104
Object[] mocks = {binder, binding, scope };
103105

@@ -133,8 +135,9 @@ public void dbPropertyCanBeJustURL() throws Exception {
133135

134136
Capture<Provider<DataSource>> provider = new Capture<>();
135137
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
136-
expect(binding.toProvider(capture(provider))).andReturn(scope);
138+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
137139
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
140+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
138141

139142
Object[] mocks = {binder, binding, scope };
140143

@@ -171,8 +174,9 @@ public void dbHashMustHaveURLwhenMoreDetailsAreProvided() throws Exception {
171174

172175
Capture<Provider<DataSource>> provider = new Capture<>();
173176
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
174-
expect(binding.toProvider(capture(provider))).andReturn(scope);
177+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
175178
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
179+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
176180

177181
Object[] mocks = {binder, binding, scope };
178182

@@ -208,8 +212,9 @@ public void derby() throws Exception {
208212

209213
Capture<Provider<DataSource>> provider = new Capture<>();
210214
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
211-
expect(binding.toProvider(capture(provider))).andReturn(scope);
215+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
212216
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
217+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
213218

214219
Object[] mocks = {binder, binding, scope };
215220

@@ -249,8 +254,9 @@ public void db2() throws Exception {
249254

250255
Capture<Provider<DataSource>> provider = new Capture<>();
251256
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
252-
expect(binding.toProvider(capture(provider))).andReturn(scope);
257+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
253258
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
259+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
254260

255261
Object[] mocks = {binder, binding, scope };
256262

@@ -287,8 +293,9 @@ public void hsql() throws Exception {
287293

288294
Capture<Provider<DataSource>> provider = new Capture<>();
289295
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
290-
expect(binding.toProvider(capture(provider))).andReturn(scope);
296+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
291297
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
298+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
292299

293300
Object[] mocks = {binder, binding, scope };
294301

@@ -325,8 +332,9 @@ public void mariadb() throws Exception {
325332

326333
Capture<Provider<DataSource>> provider = new Capture<>();
327334
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
328-
expect(binding.toProvider(capture(provider))).andReturn(scope);
335+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
329336
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
337+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
330338

331339
Object[] mocks = {binder, binding, scope };
332340

@@ -367,8 +375,9 @@ public void mysql() throws Exception {
367375

368376
Capture<Provider<DataSource>> provider = new Capture<>();
369377
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
370-
expect(binding.toProvider(capture(provider))).andReturn(scope);
378+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
371379
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
380+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
372381

373382
Object[] mocks = {binder, binding, scope };
374383

@@ -421,8 +430,9 @@ public void dbspecific() throws Exception {
421430

422431
Capture<Provider<DataSource>> provider = new Capture<>();
423432
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
424-
expect(binding.toProvider(capture(provider))).andReturn(scope);
433+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
425434
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
435+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
426436

427437
Object[] mocks = {binder, binding, scope };
428438

@@ -466,8 +476,9 @@ public void hikariDefaultsDev() throws Exception {
466476

467477
Capture<Provider<DataSource>> provider = new Capture<>();
468478
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
469-
expect(binding.toProvider(capture(provider))).andReturn(scope);
479+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
470480
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
481+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
471482

472483
Object[] mocks = {binder, binding, scope };
473484

@@ -523,8 +534,9 @@ public void hikariOverrideDefaults() throws Exception {
523534

524535
Capture<Provider<DataSource>> provider = new Capture<>();
525536
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
526-
expect(binding.toProvider(capture(provider))).andReturn(scope);
537+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
527538
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
539+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
528540

529541
Object[] mocks = {binder, binding, scope };
530542

@@ -573,8 +585,9 @@ public void overrideDataSource() throws Exception {
573585

574586
Capture<Provider<DataSource>> provider = new Capture<>();
575587
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
576-
expect(binding.toProvider(capture(provider))).andReturn(scope);
588+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
577589
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
590+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
578591

579592
Object[] mocks = {binder, binding, scope };
580593

@@ -653,8 +666,9 @@ public void sqlserver() throws Exception {
653666

654667
Capture<Provider<DataSource>> provider = new Capture<>();
655668
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
656-
expect(binding.toProvider(capture(provider))).andReturn(scope);
669+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
657670
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
671+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
658672

659673
Object[] mocks = {binder, binding, scope };
660674

@@ -694,8 +708,10 @@ public void oracle() throws Exception {
694708

695709
Capture<Provider<DataSource>> provider = new Capture<>();
696710
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
697-
expect(binding.toProvider(capture(provider))).andReturn(scope);
711+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
698712
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
713+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
714+
699715

700716
Object[] mocks = {binder, binding, scope };
701717

@@ -735,8 +751,9 @@ public void pgsql() throws Exception {
735751

736752
Capture<Provider<DataSource>> provider = new Capture<>();
737753
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
738-
expect(binding.toProvider(capture(provider))).andReturn(scope);
754+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
739755
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
756+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
740757

741758
Object[] mocks = {binder, binding, scope };
742759

@@ -776,8 +793,9 @@ public void postgresql() throws Exception {
776793

777794
Capture<Provider<DataSource>> provider = new Capture<>();
778795
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
779-
expect(binding.toProvider(capture(provider))).andReturn(scope);
796+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
780797
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
798+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
781799

782800
Object[] mocks = {binder, binding, scope };
783801

@@ -817,8 +835,9 @@ public void sybase() throws Exception {
817835

818836
Capture<Provider<DataSource>> provider = new Capture<>();
819837
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
820-
expect(binding.toProvider(capture(provider))).andReturn(scope);
838+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
821839
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
840+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
822841

823842
Object[] mocks = {binder, binding, scope };
824843

@@ -858,8 +877,9 @@ public void firebirdsql() throws Exception {
858877

859878
Capture<Provider<DataSource>> provider = new Capture<>();
860879
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
861-
expect(binding.toProvider(capture(provider))).andReturn(scope);
880+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
862881
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
882+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
863883

864884
Object[] mocks = {binder, binding, scope };
865885

@@ -899,8 +919,9 @@ public void sqlite() throws Exception {
899919

900920
Capture<Provider<DataSource>> provider = new Capture<>();
901921
LinkedBindingBuilder<DataSource> binding = createMock(LinkedBindingBuilder.class);
902-
expect(binding.toProvider(capture(provider))).andReturn(scope);
922+
expect(binding.toProvider(capture(provider))).andReturn(scope).times(2);
903923
expect(binder.bind(Key.get(DataSource.class))).andReturn(binding);
924+
expect(binder.bind(Key.get(DataSource.class, Names.named("db")))).andReturn(binding);
904925

905926
Object[] mocks = {binder, binding, scope };
906927

jooby-netty/src/main/java/org/jooby/internal/netty/NettyRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@
4545
import java.util.Optional;
4646
import java.util.function.Function;
4747

48-
import org.jooby.fn.Collectors;
4948
import org.jooby.spi.NativeRequest;
5049
import org.jooby.spi.NativeUpload;
50+
import org.jooby.util.Collectors;
5151

5252
import com.google.common.collect.ArrayListMultimap;
5353
import com.google.common.collect.ImmutableList;

jooby-quartz/pom.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,19 @@
4545
</dependency>
4646

4747
<!-- Test dependencies -->
48+
<dependency>
49+
<groupId>org.jooby</groupId>
50+
<artifactId>jooby</artifactId>
51+
<version>${project.version}</version>
52+
<scope>test</scope>
53+
<classifier>tests</classifier>
54+
</dependency>
55+
4856
<dependency>
4957
<groupId>junit</groupId>
5058
<artifactId>junit</artifactId>
5159
<scope>test</scope>
5260
</dependency>
53-
5461
<dependency>
5562
<groupId>org.easymock</groupId>
5663
<artifactId>easymock</artifactId>

0 commit comments

Comments
 (0)