├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── de
│ │ └── chandre
│ │ └── quartz
│ │ └── spring
│ │ ├── AutowiringSpringBeanJobFactory.java
│ │ ├── QuartzPropertiesOverrideHook.java
│ │ ├── QuartzSchedulerAutoConfiguration.java
│ │ ├── QuartzSchedulerFactoryOverrideHook.java
│ │ ├── QuartzSchedulerProperties.java
│ │ ├── QuartzUtils.java
│ │ ├── listener
│ │ └── TriggerMetricsListener.java
│ │ └── queue
│ │ ├── AbstractQueueService.java
│ │ ├── AsyncQueueServiceImpl.java
│ │ ├── CallbackQueueServiceImpl.java
│ │ ├── JobCallable.java
│ │ ├── JobExecutionResult.java
│ │ ├── QueueService.java
│ │ └── QueuedInstance.java
└── resources
│ └── META-INF
│ ├── additional-spring-configuration-metadata.json
│ └── spring.factories
└── test
├── java
└── de
│ └── chandre
│ └── quartz
│ ├── context
│ ├── StaticLog.java
│ ├── TestContextConfiguration11.java
│ ├── TestContextConfiguration3.java
│ ├── TestContextConfiguration4.java
│ ├── TestContextConfiguration5.java
│ ├── TestContextConfiguration7.java
│ ├── TestContextConfiguration8.java
│ └── TestContextConfiguration9.java
│ ├── jobs
│ ├── CallbackQueuedJob.java
│ ├── SimpleCronJob.java
│ └── SimpleJob.java
│ └── spring
│ ├── app
│ ├── TestApplication.java
│ └── TestApplication2.java
│ └── test
│ ├── QuartzSchedulerAutoConfig10Test.java
│ ├── QuartzSchedulerAutoConfig11Test.java
│ ├── QuartzSchedulerAutoConfig1Test.java
│ ├── QuartzSchedulerAutoConfig2Test.java
│ ├── QuartzSchedulerAutoConfig3Test.java
│ ├── QuartzSchedulerAutoConfig4Test.java
│ ├── QuartzSchedulerAutoConfig5Test.java
│ ├── QuartzSchedulerAutoConfig6Test.java
│ ├── QuartzSchedulerAutoConfig7Test.java
│ ├── QuartzSchedulerAutoConfig8Test.java
│ └── QuartzSchedulerAutoConfig9Test.java
└── resources
├── db
└── migration
│ └── h2
│ └── V001__QuartzInitialization.sql
├── differentQuartzScheduler.properties
├── log4j2.xml
└── overriddenQuartzScheduler.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | .idea
3 | .apt_generated
4 | *.iml
5 | *.project
6 | *.classpath
7 | .settings
8 | *.fbExcludeFilterFile
9 | *.factorypath
10 | *.log
11 | /bin
12 | *.versionsBackup
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring-Boot auto configuration for Quartz Scheduler
2 |
3 | > Just a Spring-Boot starter for Quartz Scheduler.
4 |
5 | Of course there are already several starters for Quartz Scheduler, but none of them fulfill all my needs, therefore I created my own.
6 |
7 | [](https://mvnrepository.com/artifact/de.chandre.quartz)
8 | [](https://github.com/andrehertwig/spring-boot-starter-quartz/issues)
9 | [](https://github.com/andrehertwig/spring-boot-starter-quartz/blob/develop/LICENSE)
10 |
11 | This is just a spare-time project. The usage of this tool (especially in production systems) is at your own risk.
12 |
13 | # Content
14 |
15 | 1. [Requirements, Dependencies](#requirements-dependencies)
16 | 2. [Usage](#usage)
17 | 3. [Configuration Properties](#configuration-properties)
18 | 4. [Additional Things](#additional-things)
19 | 1. [Utils](#utils)
20 | 2. [Hooks](#hooks)
21 | 3. [Job interdependencies](#job-interdependencies-with-105)
22 | 5. [Recommended Maven Dependency Management](#recommended-maven-dependency-management)
23 |
24 | ## Requirements, Dependencies
25 | * spring-boot
26 | * quartz-scheduler
27 |
28 | Tested with Spring Boot
29 | * (until 1.0.2) 1.3.8, 1.4.6, 1.5.3, 1.5.6,
30 | * (since 1.0.3) 1.4.6, 1.5.10, 1.5.16, 1.5.17
31 |
32 | ## Usage
33 |
34 | ```xml
35 |
36 |
37 | de.chandre.quartz
38 | spring-boot-starter-quartz
39 | 1.0.5
40 |
41 |
42 | ```
43 |
44 | Maybe you have to explicitly enable the component scan for the package:
45 | ```java
46 |
47 | @SpringBootApplication
48 | @EnableAutoConfiguration
49 | @ComponentScan(basePackages={"your.packages", "de.chandre.quartz.spring"})
50 | public class MyBootApplication {
51 |
52 | }
53 | ```
54 |
55 | ## Configuration Properties
56 |
57 | For special configuration, please check the [additional-spring-configuration-metadata.json](src/main/resources/META-INF/additional-spring-configuration-metadata.json)
58 |
59 | Original [Quartz 2.x Configuration](http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigMain.html) documentation. Please read this in case of questions how to configure Quartz correctly.
60 |
61 | ```ini
62 | # if auto configuration is enabled
63 | quartz.enabled=true
64 |
65 | ################################
66 | # Quartz Persistence #
67 | ################################
68 |
69 | # should be set to true if quartz is configured to persist its data to a database
70 | quartz.persistence.persisted=false
71 |
72 | # Only if quartz.persisted=true. if the PlatformTransactionManager should be used. Must be configured as Bean.
73 | quartz.persistence.use-platform-tx-manager=true
74 |
75 | #since 1.0.4
76 | #String
77 | #Only if quartz.persisted=true. if there are more than one PlatformTransactionManagers
78 | # within the context you can specify the bean name, which txManager to use.
79 | quartz.persistence.platform-tx-manager-bean-name=
80 |
81 | #String
82 | # Only if quartz.persisted=true. If more than one database connection is configured the
83 | # name (case-sensitive) of the used DataSource must be configured.
84 | quartz.persistence.data-source-name=
85 |
86 | ################################
87 | # Quartz SchedulerFactory #
88 | ################################
89 |
90 | #String
91 | # Optional: a name for the scheduler
92 | quartz.scheduler-factory.schedulerName=
93 |
94 | # Set whether to automatically start the scheduler after initialization.
95 | quartz.scheduler-factory.auto-startup=true
96 |
97 | # Set whether to wait for running jobs to complete on shutdown.
98 | quartz.scheduler-factory.wait-for-jobs-to-complete-on-shutdown=false
99 |
100 | # Set whether any jobs defined on this scheduler-factoryBean should overwrite existing job definitions.
101 | quartz.scheduler-factory.overwrite-existing-jobs=false
102 |
103 | # Set whether to expose the Spring-managed Scheduler instance in the Quartz SchedulerRepository.
104 | quartz.scheduler-factory.expose-scheduler-in-repository=false
105 |
106 | # Specify the phase in which this scheduler should be started and stopped.
107 | # The startup order proceeds from lowest to highest, and the shutdown order is the reverse of that.
108 | quartz.scheduler-factory.phase=java.lang.Integer.MAX_VALUE
109 |
110 | # Set the number of seconds to wait after initialization before starting the scheduler asynchronously.
111 | # Default is 0, meaning immediate synchronous startup on initialization of this bean.
112 | quartz.scheduler-factory.startup-delay=0
113 |
114 | ################################
115 | # Quartz Properties #
116 | ################################
117 |
118 | # Optional: a different resource location for quartz internal properties.
119 | # (http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigMain.html)
120 | quartz.properties-config-location=classpath:/org/quartz/quartz.properties
121 |
122 | # Optional: option to manage quartz internal properties via spring application properties.
123 | # (http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigMain.html)
124 | # you can also check org.quartz.impl.StdSchedulerFactory for static variables
125 | quartz.properties.*
126 | #example:
127 | #quartz.properties.org.quartz.scheduler.rmi.export=true
128 |
129 | # If true, the properties from spring application will override the exsisting
130 | # quartz properties from quartz.properties-config-location.
131 | # If false only Springs quartz.properties.* will be used with fallback to file if empty.
132 | quartz.override-config-location-properties=true
133 |
134 | ################################
135 | # Spring Boot Actuator #
136 | ################################
137 |
138 | # With 1.0.5
139 |
140 | # if set to true the TriggerMetricsListener will be added to Quartz listeners
141 | # which requires a configured CounterService and GaugeService
142 | quartz.metrics.enabled=false
143 |
144 | # listener name for Quartz. Default: class name
145 | quartz.metrics.listener-name=
146 |
147 | # if metrics for counting fired job groups is enabled
148 | quartz.metrics.enable-job-group-counter=false
149 |
150 | # if metrics for counting fired jobs should be enabled
151 | quartz.metrics.enable-job-counter=true
152 |
153 | # if metrics for counting fired triggers should be enabled
154 | quartz.metrics.enable-trigger-counter=true
155 |
156 | # if metrics for final instructions per job/trigger should be enabled
157 | quartz.metrics.enable-execution-instruction-counter=false
158 |
159 | # if metrics for gauge of fired jobs should be enabled
160 | quartz.metrics.enable-job-gauges=true
161 |
162 | # if metrics for gauge of fired triggers should be enabled
163 | quartz.metrics.enable-trigger-gauges=true
164 |
165 | ```
166 |
167 | The Property `quartz.properties.org.quartz.scheduler.instanceName` is overridden by Spring by default with the SchedulerFactory bean name. To rename it, use `quartz.scheduler-factory.schedulerName`
168 |
169 | ## Additional Things
170 |
171 | ### Utils
172 | Check `de.chandre.quartz.spring.QuartzUtils` for Builders for JobDetail, SimpleTrigger and CronTrigger
173 |
174 | ### Hooks
175 | If you want to add scheduler properties at runtime while application start-up, you are able to do that by implementing the `de.chandre.quartz.spring.QuartzPropertiesOverrideHook` (Maybe if your Configuration is stored in a database, or you want to change the Quartz table prefix with Hibernate's common table prefix).
176 |
177 | If you want to customize the SchedulerFactory, e.g. to set own task executor, you are able to do that by implementing the `de.chandre.quartz.spring.QuartzSchedulerFactoryOverrideHook`
178 |
179 | Example:
180 |
181 | ```java
182 | @Configuration
183 | @AutoConfigureBefore(QuartzSchedulerAutoConfiguration.class)
184 | public class SchedulerConfig
185 | {
186 | private static final Logger LOGGER = LogManager.getFormatterLogger(SchedulerConfig.class);
187 |
188 | private static final String QRTZ_TABLE_PREFIX_KEY = "org.quartz.jobStore.tablePrefix";
189 |
190 | private static final String QRTZ_JOB_CLASS = "org.quartz.jobStore.class";
191 |
192 | @Bean
193 | public QuartzPropertiesOverrideHook quartzPropertiesOverrideHook() {
194 | return new QuartzPropertiesOverrideHook() {
195 |
196 | @Override
197 | public Properties override(Properties quartzProperties) {
198 | String jobclazz = (String) quartzProperties.get(QRTZ_JOB_CLASS);
199 | if (!jobclazz.contains("RAMJobStore")) {
200 | String qrtzPrefix = (String) quartzProperties.get(QRTZ_TABLE_PREFIX_KEY);
201 | LOGGER.info("setting %s to %s", QRTZ_TABLE_PREFIX_KEY, MyCustomNamingStrategy.getPrefix() + qrtzPrefix);
202 | quartzProperties.put(QRTZ_TABLE_PREFIX_KEY, MyCustomNamingStrategy.getPrefix() + qrtzPrefix);
203 | }
204 | return quartzProperties;
205 | }
206 | };
207 | }
208 |
209 | @Bean
210 | public QuartzSchedulerFactoryOverrideHook quartzSchedulerFactoryOverrideHook() {
211 | return new QuartzSchedulerFactoryOverrideHook() {
212 |
213 | @Override
214 | public SchedulerFactoryBean override(SchedulerFactoryBean factory, QuartzSchedulerProperties properties,
215 | Properties quartzProperties) {
216 |
217 | // when doing this you may should not set "quartz.properties.org.quartz.threadPool.class" in properties
218 | factory.setTaskExecutor(Executors.newFixedThreadPool(10));
219 | return factory;
220 | }
221 | };
222 | }
223 | }
224 | ```
225 |
226 | ### Job interdependencies (With 1.0.5)
227 | Since 1.0.5 there are also predefined classes to queue dependent jobs. This implementation aims to jobs modifying same resources or should not run together at all.
228 |
229 | First defining the queue service
230 |
231 | ```java
232 |
233 | @Bean(name="queueService")
234 | public QueueService> callbackQueueServiceImpl() {
235 | //AsyncQueueServiceImpl or any own implemented service
236 | return new CallbackQueueServiceImpl();
237 | }
238 |
239 | ```
240 |
241 | Afterwards within the job
242 |
243 | ```java
244 |
245 | @Scope(scopeName=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
246 | public class CallbackQueuedJob implements Job, QueuedInstance
247 | {
248 | private final Log LOGGER = LogFactory.getLog(CallbackQueuedJob.class);
249 |
250 | public static String GROUP = "myGroup";
251 |
252 | @Autowired
253 | private QueueService> queueService;
254 |
255 | private JobExecutionContext context = null;
256 |
257 | @Override
258 | public String getGroup() {
259 | return GROUP;
260 | }
261 |
262 | @Override
263 | public String getName() {
264 | if (null != context) {
265 | return context.getTrigger().getKey().getName();
266 | }
267 | return QueuedInstance.super.getName();
268 | }
269 |
270 | @Override
271 | public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
272 | this.context = jobExecutionContext;
273 | Future future= queueService.queueMe(this);
274 | try {
275 | if (null != future) {
276 | JobExecutionResult jer = future.get(10000L, TimeUnit.MILLISECONDS);
277 | if (jer.getException() != null) {
278 | throw new JobExecutionException(jer.getException());
279 | }
280 | //do something else...
281 | } else {
282 | LOGGER.info("job not added " + jobExecutionContext.getTrigger().getKey().getName());
283 | }
284 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
285 | throw new JobExecutionException(e);
286 | }
287 | }
288 |
289 | @Override
290 | public boolean run() {
291 | //doing someing ...
292 | /*
293 | * can use this.context because my job bean should be a prototype
294 | */
295 | return true;
296 | }
297 | }
298 |
299 | ```
300 |
301 | ## Recommended Maven Dependency Management
302 |
303 | Because Quartz still will have some transitive dependencies you may don't want to have in your application, you should consider about the following dependency settings.
304 |
305 | ```xml
306 |
307 | org.quartz-scheduler
308 | quartz
309 | ${quartz-version}
310 |
311 |
312 | com.mchange
313 | c3p0
314 |
315 |
316 | com.mchange
317 | mchange-commons-java
318 |
319 |
320 | com.zaxxer
321 | HikariCP-java6
322 |
323 |
324 |
325 | ```
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | 4.0.0
5 |
6 | de.chandre.quartz
7 | spring-boot-starter-quartz
8 | 1.0.5
9 | jar
10 |
11 | Spring Boot Quartz Scheduler auto configuration
12 | Spring Boot Quartz Scheduler auto configuration
13 |
14 | https://github.com/andrehertwig/spring-boot-starter-quartz
15 | 2017
16 |
17 |
18 |
19 | andrehertwig
20 | André Hertwig
21 | andrehertwig@users.noreply.github.com
22 | https://github.com/andrehertwig
23 |
24 |
25 |
26 | architect
27 | developer
28 |
29 | +1
30 |
31 |
32 |
33 |
34 |
35 | MIT License
36 | http://www.opensource.org/licenses/mit-license.php
37 | repo
38 |
39 |
40 |
41 |
42 | GITHUB
43 | https://github.com/andrehertwig/spring-boot-starter-quartz/issues
44 |
45 |
46 |
47 | scm:git:git@github.com:andrehertwig/spring-boot-starter-quartz.git
48 | scm:git:git@github.com:andrehertwig/spring-boot-starter-quartz.git
49 | https://github.com/andrehertwig/spring-boot-starter-quartz
50 | spring-boot-starter-quartz-${project.version}
51 |
52 |
53 |
54 |
55 |
56 |
57 | UTF-8
58 | 1.8
59 |
60 | 1.8
61 | 1.8
62 | UTF-8
63 | 3.8.1
64 |
65 | 3.0.4
66 |
67 | 3.7.1
68 | true
69 | 2.22.1
70 | false
71 | 0.8.4
72 |
73 | [2.2.3,)
74 |
75 | 1.5.22.RELEASE
76 |
77 | 4.12
78 | 0.8.0.RELEASE
79 | 2.5.3
80 | 1.3.0
81 | 4.1.2
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | org.quartz-scheduler
92 | quartz
93 | ${quartz.version}
94 |
95 |
96 |
97 |
98 | org.springframework.boot
99 | spring-boot-dependencies
100 | pom
101 | ${spring-boot.version}
102 | import
103 |
104 |
105 |
106 | junit
107 | junit
108 | ${junit.version}
109 | test
110 |
111 |
112 |
113 | org.dbunit
114 | dbunit
115 | ${dbunit.version}
116 | test
117 |
118 |
119 | junit
120 | junit
121 |
122 |
123 |
124 |
125 | com.github.springtestdbunit
126 | spring-test-dbunit
127 | ${spring.test.dbunit.version}
128 | test
129 |
130 |
131 |
132 | com.jolbox
133 | bonecp
134 | ${bonecp.version}
135 | test
136 |
137 |
138 | com.jolbox
139 | bonecp-spring
140 | ${bonecp.version}
141 | test
142 |
143 |
144 | org.flywaydb
145 | flyway-core
146 | ${flyway.version}
147 | test
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | org.quartz-scheduler
157 | quartz
158 |
159 |
160 |
161 | org.springframework.boot
162 | spring-boot-autoconfigure
163 | true
164 |
165 |
166 | org.springframework.boot
167 | spring-boot-configuration-processor
168 | true
169 |
170 |
171 | org.springframework.boot
172 | spring-boot-actuator
173 | true
174 |
175 |
176 |
177 | org.springframework
178 | spring-context-support
179 |
180 |
181 |
182 | org.springframework
183 | spring-tx
184 |
185 |
186 |
187 |
188 | org.springframework.boot
189 | spring-boot-starter-test
190 |
191 |
192 |
193 | org.springframework.boot
194 | spring-boot-starter-web
195 | test
196 |
197 |
198 | org.springframework.boot
199 | spring-boot-starter-logging
200 |
201 |
202 |
203 |
204 | org.springframework.boot
205 | spring-boot-starter-log4j2
206 | test
207 |
208 |
209 | org.springframework.boot
210 | spring-boot-starter-tomcat
211 | test
212 |
213 |
214 | org.springframework
215 | spring-test
216 | test
217 |
218 |
219 | junit
220 | junit
221 | test
222 |
223 |
224 |
225 |
226 | org.springframework.boot
227 | spring-boot-starter-data-jpa
228 | test
229 |
230 |
231 | com.h2database
232 | h2
233 | test
234 |
235 |
236 | org.flywaydb
237 | flyway-core
238 | test
239 |
240 |
241 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 | org.apache.maven.plugins
271 | maven-compiler-plugin
272 | ${maven-compiler-plugin.version}
273 |
274 | ${maven.compiler.source}
275 | ${maven.compiler.target}
276 |
277 |
278 |
279 | org.apache.maven.plugins
280 | maven-source-plugin
281 | 3.0.1
282 |
283 |
284 | org.apache.maven.plugins
285 | maven-site-plugin
286 | ${maven-site-plugin.version}
287 |
288 |
289 | org.apache.maven.plugins
290 | maven-surefire-plugin
291 | ${maven-surefire-plugin.version}
292 |
293 |
294 | org.jacoco
295 | jacoco-maven-plugin
296 | ${jacoco-maven-plugin.version}
297 |
298 |
299 | org.codehaus.mojo
300 | versions-maven-plugin
301 | 2.2
302 |
303 |
304 | org.codehaus.mojo
305 | findbugs-maven-plugin
306 | ${findbugs-maven-plugin.version}
307 |
308 | Medium
309 | false
310 | Low
311 | true
312 | true
313 |
314 |
315 |
316 | analyze-compile
317 | compile
318 |
319 | check
320 |
321 |
322 |
323 |
324 |
325 | org.jacoco
326 | jacoco-maven-plugin
327 | ${jacoco-maven-plugin.version}
328 |
329 |
330 |
331 |
332 |
333 |
334 | org.codehaus.mojo
335 | versions-maven-plugin
336 |
337 |
338 | org.codehaus.mojo
339 | findbugs-maven-plugin
340 |
341 |
342 | org.apache.maven.plugins
343 | maven-surefire-plugin
344 |
345 | ${surefireArgLine}
346 |
347 |
348 |
349 | org.jacoco
350 | jacoco-maven-plugin
351 |
352 |
353 | pre-unit-test
354 |
355 | prepare-agent
356 |
357 |
358 | ${project.build.directory}/coverage-reports/jacoco-ut.exec
359 | surefireArgLine
360 |
361 |
362 |
363 | post-unit-test
364 | test
365 |
366 | report
367 |
368 |
369 | ${project.build.directory}/coverage-reports/jacoco-ut.exec
370 | ${project.reporting.outputDirectory}/jacoco-ut
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 | default
384 |
385 | true
386 |
387 |
388 |
389 |
390 | release
391 |
392 |
393 |
394 | oss.sonatype.org.staging
395 | Sonatype Staging Repository
396 | https://oss.sonatype.org/service/local/staging/deploy/maven2
397 |
398 |
399 |
400 |
401 |
402 |
403 | org.sonatype.plugins
404 | nexus-staging-maven-plugin
405 | 1.6.8
406 | true
407 |
408 | oss.sonatype.org.staging
409 | https://oss.sonatype.org/
410 | ${staging.id}
411 | true
412 |
413 |
414 |
415 | org.apache.maven.plugins
416 | maven-gpg-plugin
417 | 1.6
418 |
419 |
420 | sign-artifacts
421 | verify
422 |
423 | sign
424 |
425 |
426 |
427 |
428 |
429 | org.apache.maven.plugins
430 | maven-source-plugin
431 | 3.0.1
432 |
433 |
434 | attach-sources
435 |
436 | jar-no-fork
437 |
438 |
439 |
440 |
441 |
442 | org.apache.maven.plugins
443 | maven-javadoc-plugin
444 | 2.10.4
445 |
446 |
447 | attach-javadocs
448 |
449 | jar
450 |
451 |
452 |
453 |
454 | -Xdoclint:none
455 |
456 |
457 |
458 | org.apache.maven.plugins
459 | maven-scm-plugin
460 | 1.11.1
461 |
462 | ${project.artifactId}-${project.version}
463 | connection
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/AutowiringSpringBeanJobFactory.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import org.quartz.spi.TriggerFiredBundle;
4 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
5 | import org.springframework.context.ApplicationContext;
6 | import org.springframework.context.ApplicationContextAware;
7 | import org.springframework.scheduling.quartz.SpringBeanJobFactory;
8 |
9 | /**
10 | * Autowire Quartz Jobs with Spring context dependencies.
11 | *
12 | * @see "http://stackoverflow.com/questions/6990767/inject-bean-reference-into-a-quartz-job-in-spring/15211030#15211030"
13 | */
14 | public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
15 | /**
16 | * Holding an auto wire capable bean spring bean factory.
17 | */
18 | private AutowireCapableBeanFactory beanFactory;
19 |
20 | /**
21 | * Constructor that takes an auto wire capable bean spring bean factory.
22 | * @param context
23 | * auto wire capable bean spring bean factory
24 | */
25 | @Override
26 | public void setApplicationContext(final ApplicationContext context) {
27 | beanFactory = context.getAutowireCapableBeanFactory();
28 | }
29 |
30 | @Override
31 | protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { //NOPMD
32 | final Object job = super.createJobInstance(bundle);
33 | beanFactory.autowireBean(job);
34 | return job;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/QuartzPropertiesOverrideHook.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import java.util.Properties;
4 |
5 | /**
6 | * A hook to override some properties, maybe with instance-specific values after application start-up
7 | * @author André
8 | * @since 1.0.0
9 | */
10 | public interface QuartzPropertiesOverrideHook {
11 |
12 | /**
13 | * This method will be called after all properties are loaded, if configured correctly
14 | *
15 | * @param quartzProperties loaded quartz properties (could be null
!)
16 | * @return overridden properties
17 | */
18 | Properties override(Properties quartzProperties);
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/QuartzSchedulerAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import java.io.IOException;
4 | import java.util.Collection;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.Properties;
8 |
9 | import javax.sql.DataSource;
10 |
11 | import org.apache.commons.logging.Log;
12 | import org.apache.commons.logging.LogFactory;
13 | import org.quartz.JobListener;
14 | import org.quartz.Scheduler;
15 | import org.quartz.SchedulerListener;
16 | import org.quartz.Trigger;
17 | import org.quartz.TriggerListener;
18 | import org.quartz.impl.SchedulerRepository;
19 | import org.quartz.spi.JobFactory;
20 | import org.springframework.beans.BeanUtils;
21 | import org.springframework.beans.factory.BeanInitializationException;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.beans.factory.annotation.Qualifier;
24 | import org.springframework.beans.factory.config.PropertiesFactoryBean;
25 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
26 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
29 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
30 | import org.springframework.context.ApplicationContext;
31 | import org.springframework.context.annotation.Bean;
32 | import org.springframework.context.annotation.Configuration;
33 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
34 | import org.springframework.transaction.PlatformTransactionManager;
35 | import org.springframework.util.CollectionUtils;
36 | import org.springframework.util.StringUtils;
37 |
38 | import de.chandre.quartz.spring.QuartzSchedulerProperties.Persistence;
39 | import de.chandre.quartz.spring.QuartzSchedulerProperties.SchedulerFactory;
40 | import de.chandre.quartz.spring.listener.TriggerMetricsListener;
41 |
42 | /**
43 | * Spring-Boot auto-configuration for Quartz-Scheduler
44 | * @author André Hertwig
45 | * @since 1.0.0
46 | */
47 | @Configuration
48 | @EnableConfigurationProperties(QuartzSchedulerProperties.class)
49 | @ConditionalOnClass(Scheduler.class)
50 | public class QuartzSchedulerAutoConfiguration {
51 |
52 | private static final Log LOGGER = LogFactory.getLog(QuartzSchedulerAutoConfiguration.class);
53 |
54 | public static final String QUARTZ_PROPERTIES_BEAN_NAME = "quartzProperties";
55 | public static final String QUARTZ_SCHEDULER_FACTORY_BEAN_NAME = "autoSchedulerFactory";
56 | public static final String QUARTZ_JOB_FACTORY_BEAN_NAME = "autoJobFactory";
57 | public static final String QUARTZ_SCHEDULER_METRICS_LISTENER_BEAN_NAME = "quartzMetricsListener";
58 |
59 | @Configuration
60 | @ConditionalOnProperty(prefix = QuartzSchedulerProperties.PREFIX, name = "enabled", havingValue="true", matchIfMissing = true)
61 | @ConditionalOnMissingBean(name = QUARTZ_SCHEDULER_FACTORY_BEAN_NAME)
62 | protected static class SchedulerFactoryConfiguration {
63 |
64 | private static Collection getTriggers(ApplicationContext applicationContext) {
65 | Map triggers = applicationContext.getBeansOfType(Trigger.class);
66 | if (null != triggers && !triggers.isEmpty()) {
67 | return triggers.values();
68 | }
69 | return null;
70 | }
71 |
72 | private static PlatformTransactionManager getTransactionManager(ApplicationContext applicationContext, String txManagerBeanName) {
73 | Map txManagers = applicationContext.getBeansOfType(PlatformTransactionManager.class);
74 | if (null != txManagers && txManagers.size() > 0) {
75 | if (txManagers.size() == 1) {
76 | LOGGER.debug("only one txManager found, returning: " + txManagers.keySet().iterator().next());
77 | return txManagers.values().iterator().next();
78 | } else if (!StringUtils.isEmpty(txManagerBeanName)) {
79 | LOGGER.debug("more than one txManager found, try using: " + txManagerBeanName);
80 | PlatformTransactionManager txManager = txManagers.get(txManagerBeanName);
81 | if (null == txManager) {
82 | LOGGER.warn("QuartzSchedulerAutoConfiguration is configured to use " + txManagerBeanName
83 | + " as PlatformTransactionManager, but no bean for this name has been found in context!");
84 | }
85 | return txManager;
86 | } else {
87 | LOGGER.warn("QuartzSchedulerAutoConfiguration is configured to use PlatformTransactionManager, "
88 | + "but more than one has been found in context! "
89 | + "Consider using quartz.persistence.platform-tx-manager-bean-name in pallication configuration.");
90 | }
91 | } else {
92 | LOGGER.warn("QuartzSchedulerAutoConfiguration is configured to use PlatformTransactionManager, "
93 | + "but no bean of this type has been found in context!");
94 | }
95 | return null;
96 | }
97 |
98 | private static DataSource getDataSource(ApplicationContext applicationContext, Persistence persistenceSettings) {
99 | DataSource dataSource = null;
100 | Map datasources = applicationContext.getBeansOfType(DataSource.class);
101 | int dsSize = null != datasources ? datasources.size() : 0;
102 | if (null != datasources && null != persistenceSettings.getDataSourceName()) {
103 | dataSource = datasources.get(persistenceSettings.getDataSourceName());
104 | } else if (null != datasources && dsSize == 1 && null == persistenceSettings.getDataSourceName()){
105 | dataSource = datasources.values().iterator().next();
106 | }
107 |
108 | if (dataSource == null) {
109 | throw new BeanInitializationException(
110 | "A datasource is required when starting Quartz-Scheduler in persisted mode. " +
111 | "No DS found in map with size: " + dsSize + ", and configured DSName: " + persistenceSettings.getDataSourceName());
112 | }
113 | return dataSource;
114 | }
115 |
116 | private static QuartzSchedulerFactoryOverrideHook getQuartzSchedulerFactoryOverrideHook(ApplicationContext applicationContext) {
117 | try {
118 | return applicationContext.getBean(QuartzSchedulerFactoryOverrideHook.class);
119 | } catch (Exception e) {
120 | LOGGER.info("no QuartzSchedulerFactoryOverrideHook configured");
121 | LOGGER.trace(e.getMessage(), e);
122 | }
123 | return null;
124 | }
125 |
126 | @Bean(name = QUARTZ_JOB_FACTORY_BEAN_NAME)
127 | @ConditionalOnMissingBean(name = QUARTZ_JOB_FACTORY_BEAN_NAME)
128 | public JobFactory autoJobFactory(ApplicationContext applicationContext,
129 | @Autowired(required=false) QuartzSchedulerProperties properties) {
130 | if (null == properties) {
131 | LOGGER.warn("no QuartzSchedulerProperties found, consider to set quartz.enabled=true in properties");
132 | return null;
133 | }
134 | AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
135 | jobFactory.setApplicationContext(applicationContext);
136 | return jobFactory;
137 | }
138 |
139 | @Bean(name = QUARTZ_PROPERTIES_BEAN_NAME)
140 | @ConditionalOnMissingBean(name = QUARTZ_PROPERTIES_BEAN_NAME)
141 | public Properties quartzProperties(ApplicationContext applicationContext,
142 | @Autowired(required=false) QuartzSchedulerProperties properties)
143 | throws IOException {
144 |
145 | if (null == properties) {
146 | LOGGER.warn("no QuartzSchedulerProperties found, consider to set quartz.enabled=true in properties");
147 | return null;
148 | }
149 |
150 | Properties quartzProperties = null;
151 |
152 | if (properties.isOverrideConfigLocationProperties()) {
153 | //merge properties from file with springs application properties
154 | quartzProperties = loadConfigLocationProperties(applicationContext, properties);
155 | quartzProperties.putAll(properties.getProperties());
156 | } else if (null != properties.getProperties() && !properties.getProperties().isEmpty()) {
157 | // only use the spring application properties
158 | quartzProperties = getConfiguredProperties(properties);
159 | } else {
160 | // only use the properties from file
161 | quartzProperties = loadConfigLocationProperties(applicationContext, properties);
162 | }
163 |
164 | //Call the override hook to possibly change runtime data
165 | QuartzPropertiesOverrideHook hook = getQuartzPropOverrideHook(applicationContext);
166 | if (null != hook) {
167 | quartzProperties = hook.override(quartzProperties);
168 | }
169 |
170 | if (LOGGER.isDebugEnabled()) {
171 | LOGGER.debug("Quartz-Properties");
172 | quartzProperties.entrySet().forEach(entry -> {
173 | LOGGER.debug(" " + entry.getKey() + " = " + entry.getValue());
174 | });
175 | }
176 |
177 | return quartzProperties;
178 | }
179 |
180 | private static Properties getConfiguredProperties(QuartzSchedulerProperties properties) {
181 | Properties quartzProperties = new Properties();
182 | quartzProperties.putAll(properties.getProperties());
183 | return quartzProperties;
184 | }
185 |
186 | private static Properties loadConfigLocationProperties(ApplicationContext applicationContext,
187 | QuartzSchedulerProperties properties) throws IOException {
188 |
189 | String location = properties.getPropertiesConfigLocation();
190 | if(null == location || location.trim().length() == 0) {
191 | location = QuartzSchedulerProperties.DEFAULT_CONFIG_LOCATION;
192 | LOGGER.debug("using default 'quartz.properties' from classpath: " + location);
193 | } else {
194 | LOGGER.debug("using 'quartz.properties' from location: " + location);
195 | }
196 | PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
197 | propertiesFactoryBean.setLocation(applicationContext.getResource(location));
198 | propertiesFactoryBean.afterPropertiesSet();
199 | return propertiesFactoryBean.getObject();
200 | }
201 |
202 | private static QuartzPropertiesOverrideHook getQuartzPropOverrideHook(ApplicationContext applicationContext) {
203 | try {
204 | return applicationContext.getBean(QuartzPropertiesOverrideHook.class);
205 | } catch (Exception e) {
206 | LOGGER.info("no QuartzPropertiesOverrideHook configured");
207 | LOGGER.trace(e.getMessage(), e);
208 | }
209 | return null;
210 | }
211 |
212 | @Bean(name = QUARTZ_SCHEDULER_FACTORY_BEAN_NAME)
213 | @ConditionalOnMissingBean
214 | public SchedulerFactoryBean autoSchedulerFactory(ApplicationContext applicationContext, JobFactory jobFactory,
215 | @Autowired(required=false) QuartzSchedulerProperties properties,
216 | @Qualifier(QUARTZ_PROPERTIES_BEAN_NAME) Properties quartzProperties,
217 | @Autowired(required=false) List triggerListeners,
218 | @Autowired(required=false) List jobListeners,
219 | @Autowired(required=false) List schedulerListeners) {
220 |
221 | if (null == properties) {
222 | LOGGER.warn("no QuartzSchedulerProperties found, consider to set quartz.enabled=true in properties");
223 | return null;
224 | }
225 |
226 | LOGGER.debug("creating SchedulerFactory");
227 |
228 | SchedulerFactory factorySettings = properties.getSchedulerFactory();
229 | SchedulerRepository schedulerRepo = SchedulerRepository.getInstance();
230 | if (schedulerRepo.remove(QUARTZ_SCHEDULER_FACTORY_BEAN_NAME)) {
231 | LOGGER.debug("removed scheduler from SchedulerRepository with name: " + QUARTZ_SCHEDULER_FACTORY_BEAN_NAME);
232 | }
233 | if (null != factorySettings.getSchedulerName() && schedulerRepo.remove(factorySettings.getSchedulerName())) {
234 | LOGGER.debug("removed scheduler from SchedulerRepository with name: " + factorySettings.getSchedulerName());
235 | }
236 |
237 | SchedulerFactoryBean factory = BeanUtils.instantiateClass(SchedulerFactoryBean.class);
238 |
239 | factory.setApplicationContext(applicationContext);
240 | factory.setJobFactory(jobFactory);
241 |
242 | Persistence persistenceSettings = properties.getPersistence();
243 | if (persistenceSettings.isPersisted()) {
244 | factory.setDataSource(getDataSource(applicationContext, persistenceSettings));
245 | if (persistenceSettings.isUsePlatformTxManager()) {
246 | PlatformTransactionManager txManager = getTransactionManager(applicationContext, persistenceSettings.getPlatformTxManagerBeanName());
247 | if (null != txManager) {
248 | factory.setTransactionManager(txManager);
249 | }
250 | }
251 | }
252 |
253 | if (!StringUtils.isEmpty(factorySettings.getSchedulerName())) {
254 | factory.setSchedulerName(factorySettings.getSchedulerName());
255 | } else {
256 | LOGGER.debug("no SchedulerName configured, using bean name: " + QUARTZ_SCHEDULER_FACTORY_BEAN_NAME);
257 | }
258 | factory.setPhase(factorySettings.getPhase());
259 | factory.setStartupDelay(factorySettings.getStartupDelay());
260 | factory.setAutoStartup(factorySettings.isAutoStartup());
261 | factory.setWaitForJobsToCompleteOnShutdown(factorySettings.isWaitForJobsToCompleteOnShutdown());
262 | factory.setOverwriteExistingJobs(factorySettings.isOverwriteExistingJobs());
263 | factory.setExposeSchedulerInRepository(factorySettings.isExposeSchedulerInRepository());
264 |
265 | factory.setQuartzProperties(quartzProperties);
266 |
267 | if (!CollectionUtils.isEmpty(jobListeners)) {
268 | LOGGER.info("configuring " + jobListeners.size() + " job listeners");
269 | factory.setGlobalJobListeners(jobListeners.toArray(new JobListener[]{}));
270 | }
271 | if (!CollectionUtils.isEmpty(triggerListeners)) {
272 | LOGGER.info("configuring " + triggerListeners.size() + " trigger listeners");
273 | factory.setGlobalTriggerListeners(triggerListeners.toArray(new TriggerListener[]{}));
274 | }
275 | if (!CollectionUtils.isEmpty(schedulerListeners)) {
276 | LOGGER.info("configuring " + schedulerListeners.size() + " scheduler listeners");
277 | factory.setSchedulerListeners(schedulerListeners.toArray(new SchedulerListener[]{}));
278 | }
279 |
280 | Collection triggers = getTriggers(applicationContext);
281 | if (null != triggers && !triggers.isEmpty()) {
282 | factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
283 | LOGGER.info("staring scheduler factory with " + triggers.size() + " job triggers");
284 | } else {
285 | LOGGER.info("staring scheduler factory with 0 job triggers");
286 | }
287 |
288 | QuartzSchedulerFactoryOverrideHook hook = getQuartzSchedulerFactoryOverrideHook(applicationContext);
289 | if (null != hook) {
290 | factory = hook.override(factory, properties, quartzProperties);
291 | }
292 |
293 | return factory;
294 | }
295 | }
296 |
297 | @Configuration
298 | @ConditionalOnProperty(prefix = QuartzSchedulerProperties.PREFIX+".metrics", name = "enabled", havingValue="true", matchIfMissing = false)
299 | @ConditionalOnMissingBean(name = QUARTZ_SCHEDULER_METRICS_LISTENER_BEAN_NAME)
300 | @AutoConfigureBefore(name=QUARTZ_SCHEDULER_FACTORY_BEAN_NAME)
301 | protected static class SchedulerMetricsListenerConfiguration {
302 |
303 | @Bean(name = QUARTZ_SCHEDULER_METRICS_LISTENER_BEAN_NAME)
304 | @ConditionalOnMissingBean
305 | public TriggerMetricsListener schedulerMetricsListener(@Autowired(required=false) QuartzSchedulerProperties properties) {
306 | if (null == properties) {
307 | LOGGER.warn("no QuartzSchedulerProperties found, consider to set quartz.enabled=true in properties");
308 | return null;
309 | }
310 | TriggerMetricsListener listener = new TriggerMetricsListener(properties.getMetrics(),
311 | properties.getMetrics().getListenerName());
312 | return listener;
313 | }
314 | }
315 | }
316 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/QuartzSchedulerFactoryOverrideHook.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import java.util.Properties;
4 | import java.util.concurrent.Executor;
5 |
6 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
7 |
8 | /**
9 | * A hook to override some properties, maybe with instance-specific values after application start-up
10 | * @author André
11 | * @since 1.0.0
12 | */
13 | public interface QuartzSchedulerFactoryOverrideHook {
14 |
15 | /**
16 | * This method will be called after all SchedulerFactoryBean has been prepared
17 | * You are able to customize it, maybe for setting a own {@link Executor}
18 | *
19 | * @param factory
20 | * @return overridden properties
21 | */
22 | SchedulerFactoryBean override(SchedulerFactoryBean factory, QuartzSchedulerProperties properties, Properties quartzProperties);
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/QuartzSchedulerProperties.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import org.springframework.boot.context.properties.ConfigurationProperties;
7 |
8 | /**
9 | * Properties for Spring-Boot auto-configuration for Quartz-Scheduler
10 | * @author André Hertwig
11 | * @since 1.0.0
12 | */
13 | @ConfigurationProperties(prefix = QuartzSchedulerProperties.PREFIX, ignoreUnknownFields = true)
14 | public class QuartzSchedulerProperties {
15 |
16 | public static final String PREFIX = "quartz";
17 |
18 | public static final String DEFAULT_CONFIG_LOCATION = "classpath:/org/quartz/quartz.properties";
19 |
20 | /*
21 | * if auto-config is enabled
22 | */
23 | private boolean enabled = true;
24 |
25 | /*
26 | * metric settings
27 | */
28 | private Metrics metrics = new Metrics();
29 |
30 | /*
31 | * persistence settings
32 | */
33 | private Persistence persistence = new Persistence();
34 | /*
35 | * scheduler factory settings
36 | */
37 | private SchedulerFactory schedulerFactory = new SchedulerFactory();
38 | /*
39 | * properties settings
40 | */
41 | private String propertiesConfigLocation;
42 | private Map properties = new HashMap();
43 | private boolean overrideConfigLocationProperties = true;
44 |
45 | /**
46 | * if auto configuration is enabled
47 | * @return
48 | */
49 | public boolean isEnabled() {
50 | return enabled;
51 | }
52 |
53 | /**
54 | * if auto configuration is enabled
55 | * @param enabled
56 | */
57 | public void setEnabled(boolean enabled) {
58 | this.enabled = enabled;
59 | }
60 |
61 | /**
62 | * metrics settings for spring actuator
63 | * @return
64 | */
65 | public Metrics getMetrics() {
66 | return metrics;
67 | }
68 |
69 | public void setMetrics(Metrics metrics) {
70 | this.metrics = metrics;
71 | }
72 |
73 | /**
74 | * persistence settings
75 | * @return
76 | */
77 | public Persistence getPersistence() {
78 | return persistence;
79 | }
80 |
81 | public void setPersistence(Persistence persistence) {
82 | this.persistence = persistence;
83 | }
84 |
85 | /**
86 | * scheduler settings
87 | * @return
88 | */
89 | public SchedulerFactory getSchedulerFactory() {
90 | return schedulerFactory;
91 | }
92 |
93 | public void setSchedulerFactory(SchedulerFactory schedulerFactory) {
94 | this.schedulerFactory = schedulerFactory;
95 | }
96 |
97 | public static class Metrics {
98 |
99 | private boolean enabled = false;
100 | private String listenerName;
101 |
102 | private boolean enableJobGroupCounter = false;
103 | private boolean enableJobCounter = true;
104 | private boolean enableTriggerCounter = true;
105 | private boolean enableExecutionInstructionCounter = false;
106 |
107 | private boolean enableJobGauges = true;
108 | private boolean enableTriggerGauges = true;
109 |
110 | public boolean isEnabled() {
111 | return enabled;
112 | }
113 |
114 | public void setEnabled(boolean enabled) {
115 | this.enabled = enabled;
116 | }
117 |
118 | public String getListenerName() {
119 | return listenerName;
120 | }
121 |
122 | public void setListenerName(String listenerName) {
123 | this.listenerName = listenerName;
124 | }
125 |
126 | public boolean isEnableJobGroupCounter() {
127 | return enableJobGroupCounter;
128 | }
129 |
130 | public void setEnableJobGroupCounter(boolean enableJobGroupCounter) {
131 | this.enableJobGroupCounter = enableJobGroupCounter;
132 | }
133 |
134 | public boolean isEnableJobCounter() {
135 | return enableJobCounter;
136 | }
137 |
138 | public void setEnableJobCounter(boolean enableJobCounter) {
139 | this.enableJobCounter = enableJobCounter;
140 | }
141 |
142 | public boolean isEnableTriggerCounter() {
143 | return enableTriggerCounter;
144 | }
145 |
146 | public void setEnableTriggerCounter(boolean enableTriggerCounter) {
147 | this.enableTriggerCounter = enableTriggerCounter;
148 | }
149 |
150 | public boolean isEnableExecutionInstructionCounter() {
151 | return enableExecutionInstructionCounter;
152 | }
153 |
154 | public void setEnableExecutionInstructionCounter(boolean enableExecutionInstructionCounter) {
155 | this.enableExecutionInstructionCounter = enableExecutionInstructionCounter;
156 | }
157 |
158 | public boolean isEnableJobGauges() {
159 | return enableJobGauges;
160 | }
161 |
162 | public void setEnableJobGauges(boolean enableJobGauges) {
163 | this.enableJobGauges = enableJobGauges;
164 | }
165 |
166 | public boolean isEnableTriggerGauges() {
167 | return enableTriggerGauges;
168 | }
169 |
170 | public void setEnableTriggerGauges(boolean enableTriggerGauges) {
171 | this.enableTriggerGauges = enableTriggerGauges;
172 | }
173 | }
174 |
175 | public static class Persistence {
176 |
177 | private boolean persisted = false;
178 | private boolean usePlatformTxManager = true;
179 | private String platformTxManagerBeanName;
180 | private String dataSourceName;
181 |
182 | public boolean isPersisted() {
183 | return persisted;
184 | }
185 |
186 | public void setPersisted(boolean persisted) {
187 | this.persisted = persisted;
188 | }
189 |
190 | public boolean isUsePlatformTxManager() {
191 | return usePlatformTxManager;
192 | }
193 |
194 | public void setUsePlatformTxManager(boolean usePlatformTxManager) {
195 | this.usePlatformTxManager = usePlatformTxManager;
196 | }
197 |
198 | public String getPlatformTxManagerBeanName() {
199 | return platformTxManagerBeanName;
200 | }
201 |
202 | public void setPlatformTxManagerBeanName(String platformTxManagerBeanName) {
203 | this.platformTxManagerBeanName = platformTxManagerBeanName;
204 | }
205 |
206 | public String getDataSourceName() {
207 | return dataSourceName;
208 | }
209 |
210 | public void setDataSourceName(String dataSourceName) {
211 | this.dataSourceName = dataSourceName;
212 | }
213 |
214 | @Override
215 | public String toString() {
216 | StringBuilder builder = new StringBuilder();
217 | builder.append("Persistence [persisted=").append(persisted).append(", usePlatformTxManager=")
218 | .append(usePlatformTxManager).append(", dataSourceName=").append(dataSourceName).append("]");
219 | return builder.toString();
220 | }
221 | }
222 |
223 | public static class SchedulerFactory {
224 |
225 | private String schedulerName;
226 | private boolean autoStartup = true;
227 | private boolean waitForJobsToCompleteOnShutdown = false;
228 | private boolean overwriteExistingJobs = false;
229 | private boolean exposeSchedulerInRepository = false;
230 | private int phase = Integer.MAX_VALUE;
231 | private int startupDelay = 0;
232 |
233 | public String getSchedulerName() {
234 | return schedulerName;
235 | }
236 |
237 | public void setSchedulerName(String schedulerName) {
238 | this.schedulerName = schedulerName;
239 | }
240 |
241 | public boolean isAutoStartup() {
242 | return autoStartup;
243 | }
244 |
245 | public void setAutoStartup(boolean autoStartup) {
246 | this.autoStartup = autoStartup;
247 | }
248 |
249 | public boolean isWaitForJobsToCompleteOnShutdown() {
250 | return waitForJobsToCompleteOnShutdown;
251 | }
252 |
253 | public void setWaitForJobsToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
254 | this.waitForJobsToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
255 | }
256 |
257 | public boolean isOverwriteExistingJobs() {
258 | return overwriteExistingJobs;
259 | }
260 |
261 | public void setOverwriteExistingJobs(boolean overwriteExistingJobs) {
262 | this.overwriteExistingJobs = overwriteExistingJobs;
263 | }
264 |
265 | public boolean isExposeSchedulerInRepository() {
266 | return exposeSchedulerInRepository;
267 | }
268 |
269 | public void setExposeSchedulerInRepository(boolean exposeSchedulerInRepository) {
270 | this.exposeSchedulerInRepository = exposeSchedulerInRepository;
271 | }
272 |
273 | public int getPhase() {
274 | return phase;
275 | }
276 |
277 | public void setPhase(int phase) {
278 | this.phase = phase;
279 | }
280 |
281 | public int getStartupDelay() {
282 | return startupDelay;
283 | }
284 |
285 | public void setStartupDelay(int startupDelay) {
286 | this.startupDelay = startupDelay;
287 | }
288 |
289 | @Override
290 | public String toString() {
291 | StringBuilder builder = new StringBuilder();
292 | builder.append("SchedulerFactory [schedulerName=")
293 | .append(schedulerName).append(", autoStartup=").append(autoStartup)
294 | .append(", waitForJobsToCompleteOnShutdown=").append(waitForJobsToCompleteOnShutdown)
295 | .append(", overwriteExistingJobs=").append(overwriteExistingJobs)
296 | .append(", exposeSchedulerInRepository=").append(exposeSchedulerInRepository).append(", phase=")
297 | .append(phase).append(", startupDelay=").append(startupDelay).append("]");
298 | return builder.toString();
299 | }
300 | }
301 |
302 | public String getPropertiesConfigLocation() {
303 | return propertiesConfigLocation;
304 | }
305 |
306 | public void setPropertiesConfigLocation(String propertiesConfigLocation) {
307 | this.propertiesConfigLocation = propertiesConfigLocation;
308 | }
309 |
310 | public Map getProperties() {
311 | return properties;
312 | }
313 |
314 | public void setProperties(Map properties) {
315 | this.properties = properties;
316 | }
317 |
318 | public boolean isOverrideConfigLocationProperties() {
319 | return overrideConfigLocationProperties;
320 | }
321 |
322 | public void setOverrideConfigLocationProperties(boolean overrideConfigLocationProperties) {
323 | this.overrideConfigLocationProperties = overrideConfigLocationProperties;
324 | }
325 |
326 | @Override
327 | public String toString() {
328 | StringBuilder builder = new StringBuilder();
329 | builder.append("QuartzSchedulerProperties [enabled=").append(enabled).append(", metrics=").append(metrics)
330 | .append(", persistence=").append(persistence).append(", schedulerFactory=").append(schedulerFactory)
331 | .append(", propertiesConfigLocation=").append(propertiesConfigLocation).append(", properties=")
332 | .append(properties).append(", overrideConfigLocationProperties=")
333 | .append(overrideConfigLocationProperties).append("]");
334 | return builder.toString();
335 | }
336 |
337 | }
338 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/QuartzUtils.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring;
2 |
3 | import java.text.ParseException;
4 | import java.util.Date;
5 | import java.util.Map;
6 | import java.util.TimeZone;
7 |
8 | import org.quartz.CronTrigger;
9 | import org.quartz.Job;
10 | import org.quartz.JobDetail;
11 | import org.quartz.SimpleTrigger;
12 | import org.quartz.Trigger;
13 | import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
14 | import org.springframework.scheduling.quartz.JobDetailFactoryBean;
15 | import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
16 |
17 | /**
18 | * Convenience methods for creating {@link JobDetail}s and {@link Trigger}s for a Spring managed environment
19 | *
20 | * @author André Hertwig
21 | * @since 1.0.0
22 | */
23 | public class QuartzUtils {
24 |
25 | private QuartzUtils() {}
26 |
27 | /**
28 | *
29 | * @return build wrapper for JobDetail
30 | */
31 | public static QuartzJobBuilder jobBuilder() {
32 | return QuartzJobBuilder.builder();
33 | }
34 |
35 | /**
36 | * build wrapper for JobDetail
37 | * @since 1.0.0
38 | */
39 | public static class QuartzJobBuilder {
40 | private final JobDetailFactoryBean jobDetailFactoryBean;
41 |
42 | /**
43 | * creates a job builder. you have to call {@link #build()} afterwards to get the object
44 | */
45 | public static QuartzJobBuilder builder() {
46 | return new QuartzJobBuilder();
47 | }
48 |
49 | /**
50 | * creates a job builder. you have to call {@link #build()} afterwards to get the object
51 | */
52 | public QuartzJobBuilder() {
53 | jobDetailFactoryBean = new JobDetailFactoryBean();
54 | }
55 | /**
56 | * @see JobDetailFactoryBean#setJobClass(Class)
57 | * @param clazz
58 | * @return
59 | */
60 | public QuartzJobBuilder jobClass(Class> clazz) {
61 | jobDetailFactoryBean.setJobClass(clazz);
62 | return this;
63 | }
64 | /**
65 | * @see JobDetailFactoryBean#setBeanName(String)
66 | * @param beanName
67 | * @return
68 | */
69 | public QuartzJobBuilder beanName(String beanName) {
70 | jobDetailFactoryBean.setBeanName(beanName);
71 | return this;
72 | }
73 | /**
74 | * @see JobDetailFactoryBean#setName(String)
75 | * @param name
76 | * @return
77 | */
78 | public QuartzJobBuilder name(String name) {
79 | jobDetailFactoryBean.setName(name);
80 | return this;
81 | }
82 | /**
83 | * @see JobDetailFactoryBean#setGroup(String)
84 | * @param group
85 | * @return
86 | */
87 | public QuartzJobBuilder group(String group) {
88 | jobDetailFactoryBean.setGroup(group);
89 | return this;
90 | }
91 | /**
92 | * @see JobDetailFactoryBean#setDescription(String)
93 | * @param description
94 | * @return
95 | */
96 | public QuartzJobBuilder description(String description) {
97 | jobDetailFactoryBean.setDescription(description);
98 | return this;
99 | }
100 | /**
101 | * @see JobDetailFactoryBean#setDurability(boolean)
102 | * @param durability
103 | * @return
104 | */
105 | public QuartzJobBuilder durability(boolean durability) {
106 | jobDetailFactoryBean.setDurability(durability);
107 | return this;
108 | }
109 | /**
110 | * @see JobDetailFactoryBean#setRequestsRecovery(boolean)
111 | * @param requestRecovery
112 | * @return
113 | */
114 | public QuartzJobBuilder requestRecovery(boolean requestRecovery) {
115 | jobDetailFactoryBean.setRequestsRecovery(requestRecovery);
116 | return this;
117 | }
118 | /**
119 | * @see JobDetailFactoryBean#setJobDataAsMap(Map)
120 | * @param jobData
121 | * @return
122 | */
123 | public QuartzJobBuilder putJobData(Map jobData) {
124 | if (null != jobData) {
125 | jobDetailFactoryBean.getJobDataMap().putAll(jobData);
126 | }
127 | return this;
128 | }
129 | /**
130 | * @see JobDetailFactoryBean#setJobDataAsMap(Map)
131 | * @param key
132 | * @param value
133 | * @return
134 | */
135 | public QuartzJobBuilder addJobData(String key, Object value) {
136 | jobDetailFactoryBean.getJobDataMap().put(key, value);
137 | return this;
138 | }
139 | /**
140 | *
141 | * @return
142 | */
143 | public JobDetailFactoryBean getJobDetailFactoryBean() {
144 | return jobDetailFactoryBean;
145 | }
146 | /**
147 | *
148 | * @return
149 | */
150 | public JobDetail build() {
151 | jobDetailFactoryBean.afterPropertiesSet();
152 | return jobDetailFactoryBean.getObject();
153 | }
154 | }
155 |
156 | /**
157 | * creates a durable job detail factory bean to put into spring context
158 | *
159 | *
160 | * {@literal @}Bean
161 | * public JobDetailFactoryBean simpleJobDetail() {
162 | * return QuartzJobUtils.createJobDetail(SimpleJob.class, "MySimpleJob", null, "Just a Simple Job", null);
163 | * }
164 | *
165 | * Your job class should implement the interface {@link Job}
166 | *
167 | * @param jobClass
168 | * @param jobName (optional)
169 | * @param jobGroup (optional)
170 | * @param jobDdescription (optional)
171 | * @param jobData (optional)
172 | * @return job detail factory
173 | */
174 | public static JobDetailFactoryBean createJobDetail(Class> jobClass, String jobName, String jobGroup,
175 | String jobDdescription, Map jobData) {
176 | return QuartzUtils.jobBuilder().jobClass(jobClass).name(jobName).group(jobGroup).description(jobDdescription)
177 | .putJobData(jobData).durability(true).getJobDetailFactoryBean();
178 | }
179 |
180 | /**
181 | * returns a job detail factory bean to put into spring context
182 | *
183 | *
184 | *
185 | * {@literal @}Bean
186 | * public JobDetailFactoryBean simpleJobDetail() {
187 | * return QuartzJobUtils.createJobDetail(SimpleJob.class, "MySimpleJob", null, "Just a Simple Job", null, true, false);
188 | * }
189 | *
190 | * Your job class should implement the interface {@link Job}
191 | *
192 | * @param jobClass
193 | * @param jobName (optional)
194 | * @param jobGroup (optional)
195 | * @param jobDdescription (optional)
196 | * @param jobData (optional)
197 | * @param durable
198 | * @param requestsRecovery
199 | *
200 | * @return job detail factory
201 | */
202 | public static JobDetailFactoryBean createJobDetail(Class> jobClass, String jobName, String jobGroup,
203 | String jobDdescription, Map jobData, boolean durable, boolean requestsRecovery) {
204 |
205 | return QuartzUtils.jobBuilder().jobClass(jobClass).name(jobName).group(jobGroup).description(jobDdescription)
206 | .putJobData(jobData).durability(durable).requestRecovery(requestsRecovery).getJobDetailFactoryBean();
207 | }
208 |
209 | /**
210 | *
211 | * @return build wrapper for simple trigger
212 | */
213 | public static QuartzSimpleTriggerBuilder simpleTriggerBuilder() {
214 | return QuartzSimpleTriggerBuilder.builder();
215 | }
216 |
217 | /**
218 | * build wrapper for SimpleTrigger
219 | * @since 1.0.0
220 | */
221 | public static class QuartzSimpleTriggerBuilder {
222 | private final SimpleTriggerFactoryBean triggerFactoryBean;
223 |
224 | /**
225 | * creates a simple trigger builder. you have to call {@link #build()} afterwards to get the object
226 | */
227 | public static QuartzSimpleTriggerBuilder builder() {
228 | return new QuartzSimpleTriggerBuilder();
229 | }
230 |
231 | /**
232 | * creates a simple trigger builder. you have to call {@link #build()} afterwards to get the object
233 | */
234 | public QuartzSimpleTriggerBuilder() {
235 | triggerFactoryBean = new SimpleTriggerFactoryBean();
236 | }
237 | /**
238 | * @see SimpleTriggerFactoryBean#setJobDetail(JobDetail)
239 | * @param jobDetail
240 | * @return
241 | */
242 | public QuartzSimpleTriggerBuilder jobDetail(JobDetail jobDetail) {
243 | triggerFactoryBean.setJobDetail(jobDetail);
244 | return this;
245 | }
246 | /**
247 | * @see SimpleTriggerFactoryBean#setBeanName(String)
248 | * @param beanName
249 | * @return
250 | */
251 | public QuartzSimpleTriggerBuilder beanName(String beanName) {
252 | triggerFactoryBean.setBeanName(beanName);
253 | return this;
254 | }
255 | /**
256 | * @see SimpleTriggerFactoryBean#setName(String)
257 | * @param name
258 | * @return
259 | */
260 | public QuartzSimpleTriggerBuilder name(String name) {
261 | triggerFactoryBean.setName(name);
262 | return this;
263 | }
264 | /**
265 | * @see SimpleTriggerFactoryBean#setGroup(String)
266 | * @param group
267 | * @return
268 | */
269 | public QuartzSimpleTriggerBuilder group(String group) {
270 | triggerFactoryBean.setGroup(group);
271 | return this;
272 | }
273 | /**
274 | * @see SimpleTriggerFactoryBean#setDescription(String)
275 | * @param description
276 | * @return
277 | */
278 | public QuartzSimpleTriggerBuilder description(String description) {
279 | triggerFactoryBean.setDescription(description);
280 | return this;
281 | }
282 | /**
283 | * @see SimpleTriggerFactoryBean#setStartDelay(long)
284 | * @param startDelay
285 | * @return
286 | */
287 | public QuartzSimpleTriggerBuilder startDelay(long startDelay) {
288 | triggerFactoryBean.setStartDelay(startDelay);
289 | return this;
290 | }
291 | /**
292 | * @see SimpleTriggerFactoryBean#setStartTime(Date)
293 | * @param startTime
294 | * @return
295 | */
296 | public QuartzSimpleTriggerBuilder startTime(Date startTime) {
297 | triggerFactoryBean.setStartTime(startTime);
298 | return this;
299 | }
300 | /**
301 | * @see SimpleTriggerFactoryBean#setMisfireInstruction(int)
302 | * @param misfireInstruction
303 | * @return
304 | */
305 | public QuartzSimpleTriggerBuilder misfireInstruction(int misfireInstruction) {
306 | triggerFactoryBean.setMisfireInstruction(misfireInstruction);
307 | return this;
308 | }
309 | /**
310 | * @see SimpleTriggerFactoryBean#setMisfireInstructionName(String)
311 | * @param misfireInstructionName
312 | * @return
313 | */
314 | public QuartzSimpleTriggerBuilder misfireInstructionName(String misfireInstructionName) {
315 | triggerFactoryBean.setMisfireInstructionName(misfireInstructionName);
316 | return this;
317 | }
318 | /**
319 | * @see SimpleTriggerFactoryBean#setPriority(int)
320 | * @param priority
321 | * @return
322 | */
323 | public QuartzSimpleTriggerBuilder priority(int priority) {
324 | triggerFactoryBean.setPriority(priority);
325 | return this;
326 | }
327 | /**
328 | * @see SimpleTriggerFactoryBean#setRepeatCount(int)
329 | * @param repeatCount
330 | * @return
331 | */
332 | public QuartzSimpleTriggerBuilder repeatCount(int repeatCount) {
333 | triggerFactoryBean.setRepeatCount(repeatCount);
334 | return this;
335 | }
336 | /**
337 | * @see SimpleTriggerFactoryBean#setRepeatInterval(long)
338 | * @param repeatInterval
339 | * @return
340 | */
341 | public QuartzSimpleTriggerBuilder repeatInterval(long repeatInterval) {
342 | triggerFactoryBean.setRepeatInterval(repeatInterval);
343 | return this;
344 | }
345 |
346 | /**
347 | * @see SimpleTriggerFactoryBean#setJobDataAsMap(Map)
348 | * @param jobData
349 | * @return
350 | */
351 | public QuartzSimpleTriggerBuilder putJobData(Map jobData) {
352 | if (null != jobData) {
353 | triggerFactoryBean.getJobDataMap().putAll(jobData);
354 | }
355 | return this;
356 | }
357 |
358 | /**
359 | * @see SimpleTriggerFactoryBean#setJobDataAsMap(Map)
360 | * @param key
361 | * @param value
362 | * @return
363 | */
364 | public QuartzSimpleTriggerBuilder addJobData(String key, Object value) {
365 | triggerFactoryBean.getJobDataMap().put(key, value);
366 | return this;
367 | }
368 |
369 | public SimpleTriggerFactoryBean getTriggerFactoryBean() {
370 | return triggerFactoryBean;
371 | }
372 |
373 | public SimpleTrigger build() throws ParseException {
374 | triggerFactoryBean.afterPropertiesSet();
375 | return triggerFactoryBean.getObject();
376 | }
377 | }
378 |
379 | /**
380 | * creates a SimpleTriggerFactoryBean regarding the parameters with {@link SimpleTrigger#REPEAT_INDEFINITELY} and
381 | * {@link SimpleTrigger#MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT}
382 | *
383 | * @see QuartzUtils#createSimpleTrigger(JobDetail, String, String, String, long, long, int, int, Map, int)
384 | *
385 | * @param jobDetail
386 | * @param triggerName (optional)
387 | * @param triggerGroup (optional)
388 | * @param triggerDescription (optional)
389 | * @param startDelay
390 | * @param repeatInterval
391 | * @param jobData (optional)
392 | * @return
393 | */
394 | public static SimpleTriggerFactoryBean createSimpleTrigger(JobDetail jobDetail, String triggerName,
395 | String triggerGroup, String triggerDescription, long startDelay, long repeatInterval,
396 | Map jobData) {
397 |
398 | return QuartzUtils.simpleTriggerBuilder().jobDetail(jobDetail).name(triggerName).group(triggerGroup)
399 | .description(triggerDescription).startDelay(startDelay).repeatInterval(repeatInterval)
400 | .repeatCount(SimpleTrigger.REPEAT_INDEFINITELY)
401 | .misfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT)
402 | .putJobData(jobData).getTriggerFactoryBean();
403 | }
404 |
405 | /**
406 | *
407 | *
408 | * {@literal @}Bean
409 | * public SimpleTriggerFactoryBean createSimpleTrigger({@literal @}Qualifier("simpleJobDetail") JobDetail jobDetail) {
410 | * return QuartzJobUtils.createSimpleTrigger(jobDetail, null, null, "Simple trigger 1", 5000L, 60000L, SimpleTrigger.REPEAT_INDEFINITELY,
411 | * SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT, null, 1 );
412 | * }
413 | *
414 | *
415 | * @param jobDetail
416 | * @param triggerName (optional)
417 | * @param triggerGroup (optional)
418 | * @param triggerDescription (optional)
419 | * @param startDelay
420 | * @param repeatInterval for infinity: {@link SimpleTrigger#REPEAT_INDEFINITELY}
421 | * @param repeatCount
422 | * @param misfireInstruction {@link SimpleTrigger}
423 | * @param jobData (optional)
424 | * @param priority
425 | * @return
426 | */
427 | public static SimpleTriggerFactoryBean createSimpleTrigger(
428 | JobDetail jobDetail, String triggerName, String triggerGroup, String triggerDescription,
429 | long startDelay, long repeatInterval, int repeatCount, int misfireInstruction, Map jobData, int priority) {
430 |
431 | return QuartzUtils.simpleTriggerBuilder().jobDetail(jobDetail).name(triggerName).group(triggerGroup)
432 | .description(triggerDescription).startDelay(startDelay).repeatInterval(repeatInterval)
433 | .repeatCount(repeatCount).misfireInstruction(misfireInstruction).putJobData(jobData).priority(priority)
434 | .getTriggerFactoryBean();
435 | }
436 |
437 | /**
438 | *
439 | * @return build wrapper for cron trigger
440 | */
441 | public static QuartzCronTriggerBuilder cronTriggerBuilder() {
442 | return QuartzCronTriggerBuilder.builder();
443 | }
444 |
445 | /**
446 | * build wrapper for CronTrigger
447 | * @since 1.0.0
448 | */
449 | public static class QuartzCronTriggerBuilder {
450 | private final CronTriggerFactoryBean triggerFactoryBean;
451 |
452 | /**
453 | * creates a cron trigger builder. you have to call {@link #build()} afterwards to get the object
454 | */
455 | public static QuartzCronTriggerBuilder builder() {
456 | return new QuartzCronTriggerBuilder();
457 | }
458 |
459 | /**
460 | * creates a cron trigger builder. you have to call {@link #build()} afterwards to get the object
461 | */
462 | public QuartzCronTriggerBuilder() {
463 | triggerFactoryBean = new CronTriggerFactoryBean();
464 | }
465 |
466 | /**
467 | * @see CronTriggerFactoryBean#setJobDetail(JobDetail)
468 | * @param jobDetail
469 | * @return
470 | */
471 | public QuartzCronTriggerBuilder jobDetail(JobDetail jobDetail) {
472 | triggerFactoryBean.setJobDetail(jobDetail);
473 | return this;
474 | }
475 | /**
476 | * @see CronTriggerFactoryBean#setBeanName(String)
477 | * @param beanName
478 | * @return
479 | */
480 | public QuartzCronTriggerBuilder beanName(String beanName) {
481 | triggerFactoryBean.setBeanName(beanName);
482 | return this;
483 | }
484 | /**
485 | * @see CronTriggerFactoryBean#setName(String)
486 | * @param name
487 | * @return
488 | */
489 | public QuartzCronTriggerBuilder name(String name) {
490 | triggerFactoryBean.setName(name);
491 | return this;
492 | }
493 | /**
494 | * @see CronTriggerFactoryBean#setGroup(String)
495 | * @param group
496 | * @return
497 | */
498 | public QuartzCronTriggerBuilder group(String group) {
499 | triggerFactoryBean.setGroup(group);
500 | return this;
501 | }
502 | /**
503 | * @see CronTriggerFactoryBean#setDescription(String)
504 | * @param description
505 | * @return
506 | */
507 | public QuartzCronTriggerBuilder description(String description) {
508 | triggerFactoryBean.setDescription(description);
509 | return this;
510 | }
511 | /**
512 | * @see CronTriggerFactoryBean#setCronExpression(String)
513 | * @param cronExpression
514 | * @return
515 | */
516 | public QuartzCronTriggerBuilder cronExpression(String cronExpression) {
517 | triggerFactoryBean.setCronExpression(cronExpression);
518 | return this;
519 | }
520 | /**
521 | * @see CronTriggerFactoryBean#setStartDelay(long)
522 | * @param startDelay
523 | * @return
524 | */
525 | public QuartzCronTriggerBuilder startDelay(long startDelay) {
526 | triggerFactoryBean.setStartDelay(startDelay);
527 | return this;
528 | }
529 | /**
530 | * @see CronTriggerFactoryBean#setStartTime(Date)
531 | * @param startTime
532 | * @return
533 | */
534 | public QuartzCronTriggerBuilder startTime(Date startTime) {
535 | triggerFactoryBean.setStartTime(startTime);
536 | return this;
537 | }
538 | /**
539 | * @see CronTriggerFactoryBean#setMisfireInstruction(int)
540 | * @param misfireInstruction
541 | * @return
542 | */
543 | public QuartzCronTriggerBuilder misfireInstruction(int misfireInstruction) {
544 | triggerFactoryBean.setMisfireInstruction(misfireInstruction);
545 | return this;
546 | }
547 | /**
548 | * @see CronTriggerFactoryBean#setMisfireInstructionName(String)
549 | * @param misfireInstructionName
550 | * @return
551 | */
552 | public QuartzCronTriggerBuilder misfireInstructionName(String misfireInstructionName) {
553 | triggerFactoryBean.setMisfireInstructionName(misfireInstructionName);
554 | return this;
555 | }
556 | /**
557 | * @see CronTriggerFactoryBean#setPriority(int)
558 | * @param priority
559 | * @return
560 | */
561 | public QuartzCronTriggerBuilder priority(int priority) {
562 | triggerFactoryBean.setPriority(priority);
563 | return this;
564 | }
565 | /**
566 | * @see TimeZone#getTimeZone(String)
567 | * @see CronTriggerFactoryBean#setTimeZone(TimeZone)
568 | * @param timeZone
569 | * @return
570 | */
571 | public QuartzCronTriggerBuilder timeZone(String timeZone) {
572 | return this.timeZone(TimeZone.getTimeZone(timeZone));
573 | }
574 | /**
575 | * @see CronTriggerFactoryBean#setTimeZone(TimeZone)
576 | * @param timeZone
577 | * @return
578 | */
579 | public QuartzCronTriggerBuilder timeZone(TimeZone timeZone) {
580 | triggerFactoryBean.setTimeZone(timeZone);
581 | return this;
582 | }
583 | /**
584 | * @see CronTriggerFactoryBean#setJobDataAsMap(Map)
585 | * @param jobData
586 | * @return
587 | */
588 | public QuartzCronTriggerBuilder putJobData(Map jobData) {
589 | if (null != jobData) {
590 | triggerFactoryBean.getJobDataMap().putAll(jobData);
591 | }
592 | return this;
593 | }
594 | /**
595 | * @see CronTriggerFactoryBean#setJobDataAsMap(Map)
596 | * @param key
597 | * @param value
598 | * @return
599 | */
600 | public QuartzCronTriggerBuilder addJobData(String key, Object value) {
601 | triggerFactoryBean.getJobDataMap().put(key, value);
602 | return this;
603 | }
604 | /**
605 | * @see CronTriggerFactoryBean#setCalendarName(String)
606 | * @param calendarName
607 | * @return
608 | */
609 | public QuartzCronTriggerBuilder calendarName(String calendarName) {
610 | triggerFactoryBean.setCalendarName(calendarName);
611 | return this;
612 | }
613 | /**
614 | *
615 | * @return
616 | */
617 | public CronTriggerFactoryBean getTriggerFactoryBean() {
618 | return triggerFactoryBean;
619 | }
620 | /**
621 | *
622 | * @return
623 | * @throws ParseException
624 | */
625 | public CronTrigger build() throws ParseException {
626 | triggerFactoryBean.afterPropertiesSet();
627 | return triggerFactoryBean.getObject();
628 | }
629 | }
630 |
631 | /**
632 | * creates a CronTriggerFactoryBean regarding the parameters with {@link CronTrigger#MISFIRE_INSTRUCTION_DO_NOTHING}
633 | * @see QuartzUtils#createCronTrigger(JobDetail, String, String, String, String, int, Map, long, Date, String, int)
634 | *
635 | * @param jobDetail
636 | * @param triggerName (optional)
637 | * @param triggerGroup (optional)
638 | * @param triggerDescription (optional)
639 | * @param cronExpression
640 | * @param startDelay
641 | * @param jobData (optional)
642 | * @return
643 | */
644 | public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String triggerName, String triggerGroup,
645 | String triggerDescription, String cronExpression, long startDelay, Map jobData) {
646 |
647 | return QuartzUtils.cronTriggerBuilder().jobDetail(jobDetail).name(triggerName).group(triggerGroup)
648 | .description(triggerDescription).cronExpression(cronExpression).startDelay(startDelay)
649 | .misfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING).putJobData(jobData)
650 | .getTriggerFactoryBean();
651 | }
652 |
653 | /**
654 | * returns a cron trigger factory bean to put into spring context
655 | *
656 | * @param jobDetail
657 | * @param triggerName (optional)
658 | * @param triggerGroup (optional)
659 | * @param triggerDescription (optional)
660 | * @param cronExpression
661 | * @param misfireInstruction see {@link CronTrigger}
662 | * @param jobData
663 | * @param startDelay if start delay is set, startTime will be ignored
664 | * @param startTime
665 | * @param timeZone
666 | * @param priority
667 | * @return
668 | */
669 | public static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String triggerName, String triggerGroup,
670 | String triggerDescription, String cronExpression, int misfireInstruction, Map jobData,
671 | long startDelay, Date startTime, String timeZone, int priority) {
672 |
673 | return QuartzUtils.cronTriggerBuilder().jobDetail(jobDetail).name(triggerName).group(triggerGroup)
674 | .description(triggerDescription).cronExpression(cronExpression).startDelay(startDelay)
675 | .misfireInstruction(misfireInstruction).putJobData(jobData).timeZone(timeZone).startTime(startTime)
676 | .priority(priority).getTriggerFactoryBean();
677 | }
678 | }
679 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/listener/TriggerMetricsListener.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.listener;
2 |
3 | import javax.annotation.PostConstruct;
4 |
5 | import org.quartz.JobExecutionContext;
6 | import org.quartz.Trigger;
7 | import org.quartz.Trigger.CompletedExecutionInstruction;
8 | import org.quartz.listeners.TriggerListenerSupport;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.actuate.metrics.CounterService;
11 | import org.springframework.boot.actuate.metrics.GaugeService;
12 | import org.springframework.util.StringUtils;
13 |
14 | import de.chandre.quartz.spring.QuartzSchedulerProperties.Metrics;
15 |
16 | /**
17 | * Quartz metrics listener for Spring Boot actuator.
18 | * requires a CounterService and GaugeService to be configured.
19 | *
20 | * @author André
21 | * @since 1.0.5
22 | *
23 | */
24 | public class TriggerMetricsListener extends TriggerListenerSupport {
25 |
26 | public static final String SEPARATOR = ".";
27 |
28 | public static final String METRIC_PREFIX = "quartz" + SEPARATOR;
29 |
30 | public static final String METRIC_INFIX_TYPE_JOB = "job" + SEPARATOR;
31 | public static final String METRIC_INFIX_TYPE_TRIGGER = "trigger" + SEPARATOR;
32 |
33 | public static final String METRIC_SUFFIX_START = SEPARATOR + "fired";
34 | public static final String METRIC_SUFFIX_COMPLETE = SEPARATOR + "completed";
35 | public static final String METRIC_SUFFIX_MISFIRE = SEPARATOR + "misfired";
36 |
37 | private Metrics metricSettings;
38 | private String name;
39 |
40 | @Autowired(required = false)
41 | private CounterService counterService;
42 |
43 | @Autowired(required = false)
44 | private GaugeService gaugeService;
45 |
46 | public TriggerMetricsListener(Metrics metrics, String name) {
47 | this.metricSettings = metrics;
48 | this.name = StringUtils.isEmpty(name) ? getClass().getSimpleName() : name;
49 | }
50 |
51 | public boolean isActive() {
52 | return this.metricSettings.isEnabled() && (this.counterService != null || this.gaugeService != null);
53 | }
54 |
55 | @PostConstruct
56 | public void init() {
57 | getLog().info(this.getClass().getName() + " is " + (isActive() ? "active" : "deactivated"));
58 | }
59 |
60 | @Override
61 | public String getName() {
62 | return this.name;
63 | }
64 |
65 | protected void mesure(String suffix, Trigger trigger, JobExecutionContext context,
66 | CompletedExecutionInstruction triggerInstructionCode) {
67 | if (null == this.counterService && null == this.gaugeService) {
68 | return;
69 | }
70 | getLog().trace("exposing metrics");
71 |
72 | String jobKey = METRIC_PREFIX + METRIC_INFIX_TYPE_JOB + trigger.getJobKey().getGroup() + SEPARATOR
73 | + trigger.getJobKey().getName() + suffix;
74 | String triggerKey = METRIC_PREFIX + METRIC_INFIX_TYPE_TRIGGER + trigger.getKey().getGroup() + SEPARATOR
75 | + trigger.getKey().getName() + suffix;
76 |
77 | if (null != this.counterService) {
78 | if (this.metricSettings.isEnableJobGroupCounter()) {
79 | // count job group
80 | this.counterService.increment(METRIC_PREFIX + METRIC_INFIX_TYPE_JOB + trigger.getJobKey().getGroup() + suffix);
81 | }
82 | if (this.metricSettings.isEnableJobCounter()) {
83 | // count job group and job name
84 | this.counterService.increment(jobKey);
85 | }
86 | if (this.metricSettings.isEnableTriggerCounter()) {
87 | // count trigger group and trigger name
88 | this.counterService.increment(triggerKey);
89 | }
90 |
91 | // count finish code
92 | if (this.metricSettings.isEnableExecutionInstructionCounter() && null != triggerInstructionCode) {
93 | if (this.metricSettings.isEnableTriggerCounter()) {
94 | this.counterService.increment(triggerKey + SEPARATOR + triggerInstructionCode.name());
95 | }
96 | if (this.metricSettings.isEnableJobCounter()) {
97 | // if a job has more than one trigger .
98 | this.counterService.increment(jobKey + SEPARATOR + triggerInstructionCode.name());
99 | }
100 | }
101 | }
102 |
103 | if (null != context && null != this.gaugeService) {
104 | if (context.getJobRunTime() != -1) {
105 | if (this.metricSettings.isEnableTriggerGauges()) {
106 | gaugeService.submit(triggerKey, Long.valueOf(context.getJobRunTime()).doubleValue());
107 | }
108 | if (this.metricSettings.isEnableJobGauges()) {
109 | // if a job has more than one trigger .
110 | gaugeService.submit(jobKey, Long.valueOf(context.getJobRunTime()).doubleValue());
111 | }
112 | }
113 | }
114 |
115 | }
116 |
117 | @Override
118 | public void triggerFired(Trigger trigger, JobExecutionContext context) {
119 | mesure(METRIC_SUFFIX_START, trigger, context, null);
120 | }
121 |
122 | @Override
123 | public void triggerMisfired(Trigger trigger) {
124 | mesure(METRIC_SUFFIX_MISFIRE, trigger, null, null);
125 | }
126 |
127 | @Override
128 | public void triggerComplete(Trigger trigger, JobExecutionContext context,
129 | CompletedExecutionInstruction triggerInstructionCode) {
130 | mesure(METRIC_SUFFIX_COMPLETE, trigger, context, triggerInstructionCode);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/AbstractQueueService.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.Collections;
6 | import java.util.List;
7 | import java.util.concurrent.ExecutorService;
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.function.Function;
10 |
11 | import org.apache.commons.logging.Log;
12 |
13 | /**
14 | *
15 | * @author André
16 | * @since 1.0.5
17 | *
18 | * @param
19 | */
20 | public abstract class AbstractQueueService implements QueueService {
21 |
22 | private long waitForTerminationTime = 10000L;
23 |
24 | private TimeUnit waitForTerminationUnit = TimeUnit.MILLISECONDS;
25 |
26 | /**
27 | * should return a list of all active groups submitted to the queue service
28 | * @return
29 | */
30 | protected abstract Collection getGroupKeys();
31 |
32 | @Override
33 | public Collection getGroups() {
34 | List list = new ArrayList<>();
35 | list.add(QueuedInstance.DEFAULT_GROUP);
36 | Collection keys = getGroupKeys();
37 | if (null != keys) {
38 | list.addAll(getGroupKeys());
39 | }
40 | return Collections.unmodifiableList(list);
41 | }
42 |
43 | /**
44 | * This wait time is only for shutdown of the used executor services
45 | * @return 10000L per default if not set manually
46 | */
47 | public long getWaitForTerminationTime() {
48 | return waitForTerminationTime;
49 | }
50 |
51 | /**
52 | * This wait time is only for shutdown of the used executor services
53 | *
54 | * @param waitForTerminationTime a long value corresponding to {@link #setWaitForTerminationUnit(TimeUnit)}
55 | */
56 | public void setWaitForTerminationTime(long waitForTerminationTime) {
57 | this.waitForTerminationTime = waitForTerminationTime;
58 | }
59 |
60 | /**
61 | * time unit for {@link #getWaitForTerminationTime()}
62 | *
63 | * @return {@link TimeUnit#MILLISECONDS} per default if not set manually
64 | */
65 | public TimeUnit getWaitForTerminationUnit() {
66 | return waitForTerminationUnit;
67 | }
68 |
69 | /**
70 | * time unit for {@link #setWaitForTerminationTime(long)}
71 | * @param waitForTerminationUnit
72 | */
73 | public void setWaitForTerminationUnit(TimeUnit waitForTerminationUnit) {
74 | this.waitForTerminationUnit = waitForTerminationUnit;
75 | }
76 |
77 | /**
78 | * shuts down the executor service waiting the configured time and catches possible exceptions
79 | *
80 | * @param executorService
81 | * @param LOG the logger to log exceptions
82 | */
83 | protected void shutdownExecutorLogging(ExecutorService executorService, Log LOG) {
84 | executorService.shutdown();
85 | try {
86 | executorService.awaitTermination(getWaitForTerminationTime(), getWaitForTerminationUnit());
87 | } catch (InterruptedException e) {
88 | if (null != LOG) {
89 | LOG.warn("ExecutorService didn't shut down within " + getWaitForTerminationTime() + " " + getWaitForTerminationUnit());
90 | LOG.debug(e.getMessage(), e);
91 | }
92 | executorService.shutdownNow();
93 | }
94 | }
95 |
96 | /**
97 | * shuts down the executor service waiting the configured time and catches possible exceptions. applys the function in case of exception
98 | *
99 | * @param executorService
100 | * @param logException function with a Void return
101 | */
102 | protected void shutdownExecutor(ExecutorService executorService, Function logException) {
103 | executorService.shutdown();
104 | try {
105 | executorService.awaitTermination(getWaitForTerminationTime(), getWaitForTerminationUnit());
106 | } catch (InterruptedException e) {
107 | if (null != logException) {
108 | logException.apply(e);
109 | }
110 | executorService.shutdownNow();
111 | }
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/AsyncQueueServiceImpl.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.util.Collection;
4 | import java.util.Map;
5 | import java.util.Optional;
6 | import java.util.Queue;
7 | import java.util.concurrent.ConcurrentHashMap;
8 | import java.util.concurrent.ConcurrentLinkedQueue;
9 | import java.util.concurrent.ExecutorService;
10 | import java.util.concurrent.Executors;
11 |
12 | import javax.annotation.PostConstruct;
13 | import javax.annotation.PreDestroy;
14 |
15 | import org.apache.commons.logging.Log;
16 | import org.apache.commons.logging.LogFactory;
17 |
18 | /**
19 | * The async queue service puts the {@link QueuedInstance} to a queue and and returns true if the {@link QueuedInstance} was added.
20 | * Execution will happen afterwards.
21 | * For Quartz the job may finished successfully and really fast.
22 | * As alternative the {@link CallbackQueueServiceImpl} will return a result.
23 | *
24 | * @author André
25 | * @since 1.0.5
26 | */
27 | public class AsyncQueueServiceImpl extends AbstractQueueService {
28 |
29 | private static final Log LOG = LogFactory.getLog(AsyncQueueServiceImpl.class);
30 |
31 | private Map> jobQueueMap = new ConcurrentHashMap<>();
32 |
33 | private ExecutorService executorService;
34 |
35 | private boolean multipleInstancesAllowed;
36 |
37 | /**
38 | * When using this constructor only one instance with same name will be queued
39 | */
40 | public AsyncQueueServiceImpl() {
41 | this(false);
42 | }
43 |
44 | /**
45 | *
46 | * @param allowMultipleInstances to configure if more than one {@link QueuedInstance}
47 | * with same {@link QueuedInstance#getKey()} is allowed (true) ore not (false).
48 | */
49 | public AsyncQueueServiceImpl(boolean allowMultipleInstances) {
50 | super();
51 | this.multipleInstancesAllowed = allowMultipleInstances;
52 | }
53 |
54 | @PostConstruct
55 | public void init() {
56 | runQueue();
57 | }
58 |
59 | @PreDestroy
60 | public void destroy() {
61 | shutdown();
62 | }
63 |
64 | private void shutdown() {
65 | super.shutdownExecutor(executorService, e -> logException(e));
66 | this.executorService = null;
67 | this.jobQueueMap.clear();
68 | }
69 |
70 | protected Void logException(Exception e) {
71 | if (null != LOG) {
72 | LOG.warn("ExecutorService didn't shut down within " + getWaitForTerminationTime() + " " + getWaitForTerminationUnit());
73 | LOG.debug(e.getMessage(), e);
74 | }
75 | return null;
76 | }
77 |
78 | @Override
79 | public Boolean queueMe(QueuedInstance instance) {
80 | LOG.debug("try queuing job "+ instance.getKey() + " with hash: "+ instance.hashCode());
81 | Queue jobQueue = jobQueueMap.get(instance.getGroup());
82 | if (null == jobQueue) {
83 | jobQueue = new ConcurrentLinkedQueue();
84 | Queue otherJobQueue = jobQueueMap.putIfAbsent(instance.getGroup(), jobQueue);
85 | if (null != otherJobQueue) {
86 | jobQueue = otherJobQueue;
87 | }
88 | }
89 | if (!multipleInstancesAllowed) {
90 | Optional queuedInstance = jobQueue.stream().filter(qi -> qi.getName().equals(instance.getName())).findFirst();
91 | if (queuedInstance.isPresent()) {
92 | return Boolean.FALSE;
93 | }
94 | }
95 | return Boolean.valueOf(jobQueue.add(instance));
96 | }
97 |
98 | Map> getQueueMap() {
99 | return jobQueueMap;
100 | }
101 |
102 | private void runQueue() {
103 | executorService = Executors.newSingleThreadExecutor();
104 | executorService.execute(new QueueTask(this));
105 | }
106 |
107 | private static class QueueTask implements Runnable {
108 |
109 | private AsyncQueueServiceImpl service;
110 |
111 | QueueTask(AsyncQueueServiceImpl serviceInstance) {
112 | this.service = serviceInstance;
113 | }
114 | @Override
115 | public void run() {
116 |
117 | while(true) {
118 |
119 | service.getQueueMap().values().parallelStream().forEach(jobQueue -> {
120 | QueuedInstance queuedInstance = jobQueue.poll();
121 | if (null != queuedInstance) {
122 | LOG.info("starting queued quartz instance " + queuedInstance.getName());
123 | try {
124 | boolean result = queuedInstance.run();
125 | if (!result) {
126 | LOG.info("queued quartz instance " + queuedInstance.getName() + " ended with false");
127 | }
128 | } catch (Exception e) {
129 | LOG.error("queued quartz instance thowed an exception: " + queuedInstance.getName());
130 | LOG.error(e.getMessage(), e);
131 | }
132 | }
133 | });
134 | }
135 | }
136 | }
137 |
138 | @Override
139 | protected Collection getGroupKeys() {
140 | return this.jobQueueMap.keySet();
141 | }
142 |
143 | public void reset() {
144 | shutdown();
145 | this.executorService = Executors.newSingleThreadExecutor();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/CallbackQueueServiceImpl.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.util.Collection;
4 | import java.util.Collections;
5 | import java.util.Map;
6 | import java.util.Set;
7 | import java.util.concurrent.ConcurrentHashMap;
8 | import java.util.concurrent.ExecutorService;
9 | import java.util.concurrent.Executors;
10 | import java.util.concurrent.Future;
11 |
12 | import javax.annotation.PreDestroy;
13 |
14 | import org.apache.commons.logging.Log;
15 | import org.apache.commons.logging.LogFactory;
16 |
17 | /**
18 | * This service creates a {@link JobCallable} and submits it to a SingleThreadExecutor.
19 | * as a result you will get the a {@link Future} which returns a {@link JobExecutionResult} or null if no multiple instance are allowed.
20 | *
21 | * For example, if your Job implements {@link QueuedInstance} you can do the following in your execution method:
22 | *
23 | * Future future= queueService.queueMe(this);
24 | * JobExecutionResult jer = future.get(10000L, TimeUnit.MILLISECONDS);
25 | *
26 | *
27 | * @author André
28 | * @since 1.0.5
29 | */
30 | public class CallbackQueueServiceImpl extends AbstractQueueService> {
31 |
32 | private static final Log LOG = LogFactory.getLog(CallbackQueueServiceImpl.class);
33 |
34 | private ExecutorService defaultExecutorService = Executors.newSingleThreadExecutor();
35 |
36 | private Map jobQueueMap = new ConcurrentHashMap<>();
37 | private Set offeredInstances = Collections.newSetFromMap(new ConcurrentHashMap<>());
38 |
39 | private boolean multipleInstancesAllowed;
40 |
41 | /**
42 | * standard constructor which not allows multiple instances of objects with same {@link QueuedInstance#getKey()}
43 | */
44 | public CallbackQueueServiceImpl() {
45 | this(false);
46 | }
47 |
48 | /**
49 | *
50 | * @param allowMultipleInstances to configure if more than one {@link QueuedInstance}
51 | * with same {@link QueuedInstance#getKey()} is allowed (true) ore not (false).
52 | */
53 | public CallbackQueueServiceImpl(boolean allowMultipleInstances) {
54 | super();
55 | this.multipleInstancesAllowed = allowMultipleInstances;
56 | }
57 |
58 |
59 | @PreDestroy
60 | public void destroy() {
61 | shutdown();
62 | }
63 |
64 | private void shutdown() {
65 |
66 | super.shutdownExecutor(defaultExecutorService, e -> logException(e));
67 | this.defaultExecutorService = null;
68 | this.jobQueueMap.values().stream().parallel().forEach(executor -> shutdownExecutor(executor, e -> logException(e)));
69 | this.jobQueueMap.clear();
70 | this.offeredInstances.clear();
71 | }
72 |
73 | protected Void logException(Exception e) {
74 | if (null != LOG) {
75 | LOG.warn("ExecutorService didn't shut down within " + getWaitForTerminationTime() + " " + getWaitForTerminationUnit());
76 | LOG.debug(e.getMessage(), e);
77 | }
78 | return null;
79 | }
80 |
81 | @Override
82 | public Future queueMe(QueuedInstance instance) {
83 | String instanceKey = instance.getKey();
84 | LOG.debug("try queuing job "+ instanceKey + " with hash: "+ instance.hashCode());
85 |
86 | if (!multipleInstancesAllowed && offeredInstances.contains(instanceKey)) {
87 | return null;
88 | }
89 | offeredInstances.add(instanceKey);
90 | JobCallable callable = new JobCallable(instance, offeredInstances);
91 |
92 | Future callResult = null;
93 | if (QueuedInstance.DEFAULT_GROUP.equals(instance.getGroup())) {
94 | callResult = this.defaultExecutorService.submit(callable);
95 | } else {
96 | ExecutorService executorService = this.jobQueueMap.get(instance.getGroup());
97 | if (null == executorService) {
98 | executorService = Executors.newSingleThreadExecutor();
99 | ExecutorService otherExecutorService = this.jobQueueMap.putIfAbsent(instance.getGroup(), executorService);
100 | if (null !=otherExecutorService) {
101 | executorService = otherExecutorService;
102 | }
103 | }
104 | callResult = executorService.submit(callable);
105 | }
106 | return callResult;
107 | }
108 |
109 | @Override
110 | protected Collection getGroupKeys() {
111 | return jobQueueMap.keySet();
112 | }
113 |
114 | /**
115 | * terminates all internal executor services and creates a default new executor
116 | */
117 | public void reset() {
118 | shutdown();
119 | this.defaultExecutorService = Executors.newSingleThreadExecutor();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/JobCallable.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.util.Set;
4 | import java.util.concurrent.Callable;
5 |
6 | import org.apache.commons.logging.Log;
7 | import org.apache.commons.logging.LogFactory;
8 |
9 | /**
10 | * The callable used by {@link CallbackQueueServiceImpl}
11 | *
12 | * @author André
13 | * @since 1.0.5
14 | *
15 | */
16 | public class JobCallable implements Callable {
17 |
18 | private static final Log LOG = LogFactory.getLog(JobCallable.class);
19 |
20 | private QueuedInstance queuedInstance;
21 | private Set offeredInstances;
22 |
23 | public JobCallable(QueuedInstance queuedInstance, Set offeredInstances) {
24 | this.queuedInstance = queuedInstance;
25 | this.offeredInstances = offeredInstances;
26 | }
27 |
28 | public String getName() {
29 | return this.queuedInstance.getName();
30 | }
31 |
32 | @Override
33 | public JobExecutionResult call() throws Exception {
34 | LOG.debug("starting queued quartz instance " + queuedInstance.getName());
35 | try {
36 | if (!offeredInstances.remove(queuedInstance.getKey())) {
37 | LOG.warn("queued quartz instance " + queuedInstance.getName() + " hat not been removed from offered jobs.");
38 | }
39 | //run the logic.
40 | boolean result = queuedInstance.run();
41 | if (!result) {
42 | LOG.debug("queued quartz instance " + queuedInstance.getName() + " ended with false");
43 | }
44 | return new JobExecutionResult(result);
45 | } catch (Throwable e) {
46 | LOG.debug("queued quartz instance thowed an exception: " + queuedInstance.getName());
47 | LOG.debug(e.getMessage(), e);
48 | return new JobExecutionResult(false, e);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/JobExecutionResult.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Job execution result for callable queue service
7 | * @author André
8 | * @since 1.0.5
9 | *
10 | */
11 | public class JobExecutionResult implements Serializable {
12 | private static final long serialVersionUID = -7109542826143909L;
13 |
14 | private boolean success;
15 | private Throwable exception;
16 |
17 | public JobExecutionResult(boolean success) {
18 | this(success, null);
19 | }
20 |
21 | public JobExecutionResult(boolean success, Throwable exception) {
22 | super();
23 | this.success = success;
24 | this.exception = exception;
25 | }
26 |
27 | /**
28 | * if job returned true for {@link QueuedInstance#run()}
29 | * @return
30 | */
31 | public boolean isSuccess() {
32 | return success;
33 | }
34 |
35 | public void setSuccess(boolean success) {
36 | this.success = success;
37 | }
38 |
39 | /**
40 | * when job throws an exception
41 | * @return null or exception
42 | */
43 | public Throwable getException() {
44 | return exception;
45 | }
46 |
47 | public void setException(Throwable exception) {
48 | this.exception = exception;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | StringBuilder builder = new StringBuilder();
54 | builder.append("JobExecutionResult [success=").append(success).append(", exception=").append(exception)
55 | .append("]");
56 | return builder.toString();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/QueueService.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | import java.util.Collection;
4 |
5 | import org.quartz.listeners.JobChainingJobListener;
6 |
7 | /**
8 | * The service queuing the job object reference to be executed one after another.
9 | * This service points to depended Jobs which may use/modify same resources or should not run together at all.
10 | * If you want to be sure that Job A will run first and Job B after them, consider using the {@link JobChainingJobListener} instead.
11 | *
12 | * @author André
13 | * @since 1.0.5
14 | */
15 | public interface QueueService {
16 |
17 | /**
18 | * adds the instance to queue
19 | * @param instance the job object reference
20 | * @return the value regarding the implementations ({@link CallbackQueueServiceImpl}, {@link AsyncQueueServiceImpl})
21 | */
22 | T queueMe(QueuedInstance instance);
23 |
24 | /**
25 | * returns all active groups
26 | *
27 | * @return
28 | */
29 | Collection getGroups();
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/de/chandre/quartz/spring/queue/QueuedInstance.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.queue;
2 |
3 | /**
4 | * Interface for instances to queue in {@link QueueService}.
5 | * A job which should be queued has to implement this interface.
6 | * Furthermore a {@link QueueService} must be started and within the job you must call {@link QueueService#queueMe(QueuedInstance)}
7 | * Depending on the implementation you may have other things to do...
8 | *
9 | * @author André
10 | * @since 1.0.5
11 | */
12 | public interface QueuedInstance {
13 |
14 | String DEFAULT_GROUP = "default";
15 | String KEY_SEPARATOR = ":";
16 |
17 | /**
18 | * identification name of queue group.
19 | * @return
20 | */
21 | default String getGroup() {
22 | return DEFAULT_GROUP;
23 | };
24 |
25 | /**
26 | * identification name of object. Only one instance with same name will be queued per group.
27 | * @return
28 | */
29 | default String getName() {
30 | return getClass().getSimpleName();
31 | };
32 |
33 | /**
34 | * should return an identifier for the queued instance.
35 | * @return default: {@link #getGroup()} + {@value #KEY_SEPARATOR} + {@link #getName())
36 | */
37 | default String getKey() {
38 | return getGroup() + KEY_SEPARATOR + getName();
39 | };
40 |
41 | /**
42 | * implement your code here to be executed
43 | * @return should return true if job ended successfully
44 | */
45 | boolean run();
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/additional-spring-configuration-metadata.json:
--------------------------------------------------------------------------------
1 | {"groups": [
2 | {
3 | "name": "quartz",
4 | "type": "de.chandre.quartz.spring.QuartzSchedulerProperties",
5 | "sourceType": "de.chandre.quartz.spring.QuartzSchedulerProperties"
6 | },{
7 | "name": "quartz.metrics",
8 | "type": "de.chandre.quartz.spring.QuartzSchedulerProperties$Metrics",
9 | "sourceType": "de.chandre.quartz.spring.QuartzSchedulerProperties",
10 | "sourceMethod": "getMetrics()"
11 | },{
12 | "name": "quartz.persistence",
13 | "type": "de.chandre.quartz.spring.QuartzSchedulerProperties$Persistence",
14 | "sourceType": "de.chandre.quartz.spring.QuartzSchedulerProperties",
15 | "sourceMethod": "getPersistence()"
16 | },{
17 | "name": "quartz.scheduler-factory",
18 | "type": "de.chandre.quartz.spring.QuartzSchedulerProperties$SchedulerFactory",
19 | "sourceType": "de.chandre.quartz.spring.QuartzSchedulerProperties",
20 | "sourceMethod": "getSchedulerFactory()"
21 | }
22 | ],"properties": [
23 | {
24 | "name": "quartz.enabled",
25 | "type": "java.lang.Boolean",
26 | "description": "if auto configuration is enabled",
27 | "defaultValue": "true"
28 | },{
29 | "name": "quartz.metrics.enabled",
30 | "type": "java.lang.Boolean",
31 | "description": "if metrics configuration is enabled",
32 | "defaultValue": "false"
33 | },{
34 | "name": "quartz.metrics.listener-name",
35 | "type": "java.lang.String",
36 | "description": "Optional: a name for the MetricsListener. If no name provided by configuration the class name will be used.",
37 | "defaultValue": ""
38 | },{
39 | "name": "quartz.metrics.enable-job-group-counter",
40 | "type": "java.lang.Boolean",
41 | "description": "if metrics for counting fired job groups should be enabled",
42 | "defaultValue": "false"
43 | },{
44 | "name": "quartz.metrics.enable-job-counter",
45 | "type": "java.lang.Boolean",
46 | "description": "if metrics for counting fired jobs should be enabled",
47 | "defaultValue": "true"
48 | },{
49 | "name": "quartz.metrics.enable-trigger-counter",
50 | "type": "java.lang.Boolean",
51 | "description": "if metrics for counting fired triggers should be enabled",
52 | "defaultValue": "true"
53 | },{
54 | "name": "quartz.metrics.enable-execution-instruction-counter",
55 | "type": "java.lang.Boolean",
56 | "description": "if metrics for final instructions per job/trigger should be enabled",
57 | "defaultValue": "false"
58 | },{
59 | "name": "quartz.metrics.enable-job-gauges",
60 | "type": "java.lang.Boolean",
61 | "description": "if metrics for gauge of fired jobs should be enabled",
62 | "defaultValue": "true"
63 | },{
64 | "name": "quartz.metrics.enable-trigger-gauges",
65 | "type": "java.lang.Boolean",
66 | "description": "if metrics for gauge of fired triggers should be enabled",
67 | "defaultValue": "true"
68 | },{
69 | "name": "quartz.persistence.persisted",
70 | "type": "java.lang.Boolean",
71 | "description": "should be set to true if quartz is configured to persist its data to a database",
72 | "defaultValue": "false"
73 | },{
74 | "name": "quartz.persistence.use-platform-tx-manager",
75 | "type": "java.lang.Boolean",
76 | "description": "Only if quartz.persisted=true. if the PlatformTransactionManager should be used. Must be configured as Bean.",
77 | "defaultValue": "true"
78 | },{
79 | "name": "quartz.persistence.platform-tx-manager-bean-name",
80 | "type": "java.lang.String",
81 | "description": "Only if quartz.persisted=true. if there are more than one PlatformTransactionManagers within the context you can specify the bean name, which txManager to use.",
82 | "defaultValue": "true"
83 | },{
84 | "name": "quartz.persistence.data-source-name",
85 | "type": "java.lang.String",
86 | "description": "Only if quartz.persisted=true. If more than one database connection is configured the name (case-sensitive) of the used DataSource must be configured.",
87 | "defaultValue": ""
88 | },{
89 | "name": "quartz.scheduler-factory.schedulerName",
90 | "type": "java.lang.String",
91 | "description": "Optional: a name for the scheduler",
92 | "defaultValue": ""
93 | },{
94 | "name": "quartz.scheduler-factory.auto-startup",
95 | "type": "java.lang.Boolean",
96 | "description": "Set whether to automatically start the scheduler after initialization. ",
97 | "defaultValue": "true"
98 | },{
99 | "name": "quartz.scheduler-factory.wait-for-jobs-to-complete-on-shutdown",
100 | "type": "java.lang.Boolean",
101 | "description": "Set whether to wait for running jobs to complete on shutdown.",
102 | "defaultValue": "false"
103 | },{
104 | "name": "quartz.scheduler-factory.overwrite-existing-jobs",
105 | "type": "java.lang.Boolean",
106 | "description": "Set whether any jobs defined on this scheduler-factoryBean should overwrite existing job definitions. ",
107 | "defaultValue": "false"
108 | },{
109 | "name": "quartz.scheduler-factory.expose-scheduler-in-repository",
110 | "type": "java.lang.Boolean",
111 | "description": "Set whether to expose the Spring-managed Scheduler instance in the Quartz SchedulerRepository.",
112 | "defaultValue": "false"
113 | },{
114 | "name": "quartz.scheduler-factory.phase",
115 | "type": "java.lang.Integer",
116 | "description": "Specify the phase in which this scheduler should be started and stopped. The startup order proceeds from lowest to highest, and the shutdown order is the reverse of that.",
117 | "defaultValue": "java.lang.Integer.MAX_VALUE"
118 | },{
119 | "name": "quartz.scheduler-factory.startup-delay",
120 | "type": "java.lang.Integer",
121 | "description": "Set the number of seconds to wait after initialization before starting the scheduler asynchronously. Default is 0, meaning immediate synchronous startup on initialization of this bean. ",
122 | "defaultValue": "0"
123 | },{
124 | "name": "quartz.properties-config-location",
125 | "type": "java.lang.String",
126 | "description": "Optional: a different resource location for quartz internal properties. (http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigMain.html)",
127 | "defaultValue": "classpath:/org/quartz/quartz.properties"
128 | },{
129 | "name": "quartz.properties",
130 | "type": "java.util.Map",
131 | "description": "Optional: option to manage quartz internal properties via spring application properties. (http://www.quartz-scheduler.org/documentation/quartz-2.x/configuration/ConfigMain.html)",
132 | "defaultValue": ""
133 | },{
134 | "name": "quartz.override-config-location-properties",
135 | "type": "java.lang.Boolean",
136 | "description": "If true, the properties from spring application will override the exsisting quartz properties from quartz.properties-config-location. If false only Springs quartz.properties.* will be used with fallback to file if empty.",
137 | "defaultValue": "true"
138 | }
139 | ]}
--------------------------------------------------------------------------------
/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/StaticLog.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Simple message appender to unit tests
8 | * @author André Hertwig
9 | */
10 | public class StaticLog {
11 | private static StaticLog LOG = new StaticLog();
12 | private List messasges = new ArrayList<>();
13 |
14 | private StaticLog() {
15 | super();
16 | clear();
17 | }
18 |
19 | public static StaticLog getInstance() {
20 | return LOG;
21 | }
22 |
23 | public List getMessasges() {
24 | return messasges;
25 | }
26 |
27 | public void addMessasge(String messasge) {
28 | this.messasges.add(messasge);
29 | }
30 |
31 | public void clear() {
32 | this.messasges.clear();;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration11.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.util.Date;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 | import java.util.concurrent.Future;
7 |
8 | import org.quartz.CronTrigger;
9 | import org.quartz.JobDetail;
10 | import org.quartz.SimpleTrigger;
11 | import org.springframework.beans.factory.annotation.Qualifier;
12 | import org.springframework.context.annotation.Bean;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
15 | import org.springframework.scheduling.quartz.JobDetailFactoryBean;
16 | import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
17 |
18 | import de.chandre.quartz.jobs.CallbackQueuedJob;
19 | import de.chandre.quartz.jobs.SimpleCronJob;
20 | import de.chandre.quartz.jobs.SimpleJob;
21 | import de.chandre.quartz.spring.QuartzUtils;
22 | import de.chandre.quartz.spring.queue.CallbackQueueServiceImpl;
23 | import de.chandre.quartz.spring.queue.JobExecutionResult;
24 | import de.chandre.quartz.spring.queue.QueueService;
25 |
26 | @Configuration
27 | public class TestContextConfiguration11 {
28 |
29 | public static final String SIMPLE_JOB_NAME = "SimpleJobName";
30 | public static final String SIMPLE_JOB_GROUP = "SimpleJobGroup";
31 | public static final String CRON_JOB_NAME = "CronJobName";
32 | public static final String CRON_JOB_GROUP = "CronJobGroup";
33 | public static final String CALLBACK_JOB_NAME = "CallbackJobName";
34 | public static final String CALLBACK_JOB_GROUP = "CallbackJobGroup";
35 |
36 | @Bean(name="simpleJobDetail")
37 | public JobDetailFactoryBean simpleJobDetail() {
38 | return QuartzUtils.createJobDetail(SimpleJob.class, SIMPLE_JOB_NAME, SIMPLE_JOB_GROUP, "Just a Simple Job", null);
39 | }
40 |
41 | @Bean(name="simpleJobTrigger")
42 | public SimpleTriggerFactoryBean createSimpleTrigger(@Qualifier("simpleJobDetail") JobDetail jobDetail) {
43 | return QuartzUtils.createSimpleTrigger(jobDetail, null, null, "Simple trigger 1", 5000L, 60000L, null);
44 | }
45 |
46 | @Bean(name="simpleJobTrigger2")
47 | public SimpleTriggerFactoryBean createSimpleTrigger2(@Qualifier("simpleJobDetail") JobDetail jobDetail) {
48 | Map map = new HashMap<>(1);
49 | map.put("myKey", "myValue");
50 | return QuartzUtils.createSimpleTrigger(jobDetail, "STName2", "STGroup2", "STDesc2", 10000L, 30000L,
51 | SimpleTrigger.REPEAT_INDEFINITELY,
52 | SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT, map, 1000);
53 | }
54 |
55 |
56 | @Bean(name="cronJobDetail")
57 | public JobDetailFactoryBean cronJobDetail() {
58 | return QuartzUtils.createJobDetail(SimpleCronJob.class, CRON_JOB_NAME, CRON_JOB_GROUP, "Just a Cron Job", null);
59 | }
60 |
61 | @Bean(name="cronTrigger")
62 | public CronTriggerFactoryBean createSimpleCronTrigger(@Qualifier("cronJobDetail") JobDetail jobDetail) {
63 | return QuartzUtils.createCronTrigger(jobDetail, null, "Cron", null, "0 0 0/1 1/1 * ? *", 5000L, null);
64 | }
65 |
66 | @Bean(name="cronTrigger2")
67 | public CronTriggerFactoryBean createSimpleCronTrigger2(@Qualifier("cronJobDetail") JobDetail jobDetail) {
68 | Map map = new HashMap<>(1);
69 | map.put("myKey", "myValue");
70 | return QuartzUtils.createCronTrigger(jobDetail, "CTName2", "Cron", "CTDesc2", "0 0 0/1 1/1 * ? *",
71 | CronTrigger.MISFIRE_INSTRUCTION_SMART_POLICY, map, 10000L, new Date(), "Europe/Berlin", 1234);
72 | }
73 |
74 |
75 | @Bean(name="queueService")
76 | public QueueService> callbackQueueServiceImpl() {
77 | CallbackQueueServiceImpl cbqs = new CallbackQueueServiceImpl();
78 | cbqs.setWaitForTerminationTime(1000L);
79 | return cbqs;
80 | }
81 |
82 | @Bean(name="callbackJobDetail")
83 | public JobDetailFactoryBean callbackJobDetail() {
84 | return QuartzUtils.createJobDetail(CallbackQueuedJob.class, CALLBACK_JOB_NAME, CALLBACK_JOB_GROUP, "Callback Job", null);
85 | }
86 |
87 | @Bean(name = "callbackJobTrigger")
88 | public SimpleTriggerFactoryBean createCallbackTrigger(@Qualifier("callbackJobDetail") JobDetail jobDetail) {
89 | return QuartzUtils.simpleTriggerBuilder().jobDetail(jobDetail).name("CallbackTrigger1").startDelay(5L)
90 | .repeatInterval(100L).repeatCount(20).getTriggerFactoryBean();
91 | }
92 |
93 | @Bean(name = "callbackJobTrigger2")
94 | public SimpleTriggerFactoryBean createCallbackTrigger2(@Qualifier("callbackJobDetail") JobDetail jobDetail) {
95 | return QuartzUtils.simpleTriggerBuilder().jobDetail(jobDetail).name("CallbackTrigger2").startDelay(5L)
96 | .repeatInterval(100L).repeatCount(20).getTriggerFactoryBean();
97 | }
98 |
99 | @Bean(name = "callbackJobTrigger3")
100 | public SimpleTriggerFactoryBean createCallbackTrigger3(@Qualifier("callbackJobDetail") JobDetail jobDetail) {
101 | return QuartzUtils.simpleTriggerBuilder().jobDetail(jobDetail).name("CallbackTrigger3").startDelay(5L)
102 | .repeatInterval(100L).repeatCount(20).getTriggerFactoryBean();
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration3.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.io.IOException;
4 | import java.util.Properties;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.beans.factory.config.PropertiesFactoryBean;
8 | import org.springframework.context.ApplicationContext;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
13 | import de.chandre.quartz.spring.QuartzSchedulerProperties;
14 |
15 | @Configuration
16 | public class TestContextConfiguration3 {
17 |
18 | @Bean(name = QuartzSchedulerAutoConfiguration.QUARTZ_PROPERTIES_BEAN_NAME)
19 | public Properties quartzProperties(
20 | @Autowired ApplicationContext applicationContext,
21 | @Autowired QuartzSchedulerProperties properties) throws IOException {
22 |
23 | System.out.println("my overridden quartz.properties loading");
24 |
25 | PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
26 | propertiesFactoryBean.setLocation(applicationContext.getResource("classpath:overriddenQuartzScheduler.properties"));
27 | propertiesFactoryBean.afterPropertiesSet();
28 | return propertiesFactoryBean.getObject();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration4.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.util.Date;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | import org.quartz.CronTrigger;
8 | import org.quartz.JobDetail;
9 | import org.quartz.SimpleTrigger;
10 | import org.springframework.beans.factory.annotation.Qualifier;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.Configuration;
13 | import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
14 | import org.springframework.scheduling.quartz.JobDetailFactoryBean;
15 | import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
16 |
17 | import de.chandre.quartz.jobs.SimpleCronJob;
18 | import de.chandre.quartz.jobs.SimpleJob;
19 | import de.chandre.quartz.spring.QuartzUtils;
20 |
21 | @Configuration
22 | public class TestContextConfiguration4 {
23 |
24 | public static final String SIMPLE_JOB_NAME = "SimpleJobName";
25 | public static final String SIMPLE_JOB_GROUP = "SimpleJobGroup";
26 | public static final String CRON_JOB_NAME = "CronJobName";
27 | public static final String CRON_JOB_GROUP = "CronJobGroup";
28 |
29 | @Bean(name="simpleJobDetail")
30 | public JobDetailFactoryBean simpleJobDetail() {
31 | return QuartzUtils.createJobDetail(SimpleJob.class, SIMPLE_JOB_NAME, SIMPLE_JOB_GROUP, "Just a Simple Job", null);
32 | }
33 |
34 | @Bean(name="simpleJobTrigger")
35 | public SimpleTriggerFactoryBean createSimpleTrigger(@Qualifier("simpleJobDetail") JobDetail jobDetail) {
36 | return QuartzUtils.createSimpleTrigger(jobDetail, null, null, "Simple trigger 1", 5000L, 60000L, null);
37 | }
38 |
39 | @Bean(name="simpleJobTrigger2")
40 | public SimpleTriggerFactoryBean createSimpleTrigger2(@Qualifier("simpleJobDetail") JobDetail jobDetail) {
41 | Map map = new HashMap<>(1);
42 | map.put("myKey", "myValue");
43 | return QuartzUtils.createSimpleTrigger(jobDetail, "STName2", "STGroup2", "STDesc2", 10000L, 30000L,
44 | SimpleTrigger.REPEAT_INDEFINITELY,
45 | SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT, map, 1000);
46 | }
47 |
48 |
49 | @Bean(name="cronJobDetail")
50 | public JobDetailFactoryBean cronJobDetail() {
51 | return QuartzUtils.createJobDetail(SimpleCronJob.class, CRON_JOB_NAME, CRON_JOB_GROUP, "Just a Cron Job", null);
52 | }
53 |
54 | @Bean(name="cronTrigger")
55 | public CronTriggerFactoryBean createSimpleCronTrigger(@Qualifier("cronJobDetail") JobDetail jobDetail) {
56 | return QuartzUtils.createCronTrigger(jobDetail, null, "Cron", null, "0 0 0/1 1/1 * ? *", 5000L, null);
57 | }
58 |
59 | @Bean(name="cronTrigger2")
60 | public CronTriggerFactoryBean createSimpleCronTrigger2(@Qualifier("cronJobDetail") JobDetail jobDetail) {
61 | Map map = new HashMap<>(1);
62 | map.put("myKey", "myValue");
63 | return QuartzUtils.createCronTrigger(jobDetail, "CTName2", "Cron", "CTDesc2", "0 0 0/1 1/1 * ? *",
64 | CronTrigger.MISFIRE_INSTRUCTION_SMART_POLICY, map, 10000L, new Date(), "Europe/Berlin", 1234);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration5.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.util.Properties;
4 |
5 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
9 |
10 | import de.chandre.quartz.spring.QuartzPropertiesOverrideHook;
11 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
12 | import de.chandre.quartz.spring.QuartzSchedulerFactoryOverrideHook;
13 | import de.chandre.quartz.spring.QuartzSchedulerProperties;
14 |
15 | @Configuration
16 | @AutoConfigureBefore(QuartzSchedulerAutoConfiguration.class)
17 | public class TestContextConfiguration5 {
18 |
19 | public static final String CAPTURE1 = "captured: overriding quartz props";
20 | public static final String CAPTURE2 = "captured: overriding quartz factory";
21 |
22 | @Bean
23 | public QuartzPropertiesOverrideHook quartzPropertiesOverrideHook() {
24 | return new QuartzPropertiesOverrideHook() {
25 |
26 | @Override
27 | public Properties override(Properties quartzProperties) {
28 | StaticLog.getInstance().addMessasge(CAPTURE1);
29 | return quartzProperties;
30 | }
31 | };
32 | }
33 |
34 | @Bean
35 | public QuartzSchedulerFactoryOverrideHook quartzSchedulerFactoryOverrideHook() {
36 | return new QuartzSchedulerFactoryOverrideHook() {
37 |
38 | @Override
39 | public SchedulerFactoryBean override(SchedulerFactoryBean factory, QuartzSchedulerProperties properties,
40 | Properties quartzProperties) {
41 | StaticLog.getInstance().addMessasge(CAPTURE2);
42 | return factory;
43 | }
44 | };
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration7.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import javax.sql.DataSource;
4 |
5 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.context.annotation.Primary;
9 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
10 | import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
11 |
12 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
13 |
14 | @Configuration
15 | @AutoConfigureBefore(QuartzSchedulerAutoConfiguration.class)
16 | public class TestContextConfiguration7 {
17 |
18 | @Bean("dataSource")
19 | public DataSource dataSource() {
20 |
21 | return new EmbeddedDatabaseBuilder().generateUniqueName(true)
22 | .setType(EmbeddedDatabaseType.H2)
23 | .setScriptEncoding("UTF-8")
24 | .ignoreFailedDrops(true).build();
25 | }
26 |
27 | @Bean("otherDataSource")
28 | @Primary
29 | public DataSource otherDataSource() {
30 |
31 | return new EmbeddedDatabaseBuilder().generateUniqueName(true)
32 | .setType(EmbeddedDatabaseType.H2)
33 | .setScriptEncoding("UTF-8")
34 | .ignoreFailedDrops(true).build();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration8.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.orm.jpa.JpaTransactionManager;
7 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
8 | import org.springframework.transaction.PlatformTransactionManager;
9 |
10 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
11 |
12 | @Configuration
13 | @AutoConfigureBefore(QuartzSchedulerAutoConfiguration.class)
14 | public class TestContextConfiguration8 {
15 |
16 | @Bean
17 | public PlatformTransactionManager firstTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) {
18 | JpaTransactionManager transactionManager = new JpaTransactionManager();
19 | transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
20 | return transactionManager;
21 | }
22 |
23 | @Bean
24 | public PlatformTransactionManager secondTransactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) {
25 | JpaTransactionManager transactionManager = new JpaTransactionManager();
26 | transactionManager.setEntityManagerFactory(entityManagerFactory.getObject());
27 | return transactionManager;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/context/TestContextConfiguration9.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.context;
2 |
3 | import java.util.Properties;
4 | import java.util.concurrent.Executors;
5 |
6 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
10 |
11 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
12 | import de.chandre.quartz.spring.QuartzSchedulerFactoryOverrideHook;
13 | import de.chandre.quartz.spring.QuartzSchedulerProperties;
14 |
15 | @Configuration
16 | @AutoConfigureBefore(QuartzSchedulerAutoConfiguration.class)
17 | public class TestContextConfiguration9 {
18 |
19 | public static final String CAPTURE1 = "captured: overriding quartz factory";
20 |
21 | @Bean
22 | public QuartzSchedulerFactoryOverrideHook quartzSchedulerFactoryOverrideHook() {
23 | return new QuartzSchedulerFactoryOverrideHook() {
24 |
25 | @Override
26 | public SchedulerFactoryBean override(SchedulerFactoryBean factory, QuartzSchedulerProperties properties,
27 | Properties quartzProperties) {
28 | factory.setTaskExecutor(Executors.newFixedThreadPool(20));
29 | StaticLog.getInstance().addMessasge(CAPTURE1);
30 | return factory;
31 | }
32 | };
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/jobs/CallbackQueuedJob.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.jobs;
2 |
3 | import java.util.concurrent.ExecutionException;
4 | import java.util.concurrent.Future;
5 | import java.util.concurrent.TimeUnit;
6 | import java.util.concurrent.TimeoutException;
7 |
8 | import org.apache.commons.logging.Log;
9 | import org.apache.commons.logging.LogFactory;
10 | import org.quartz.Job;
11 | import org.quartz.JobExecutionContext;
12 | import org.quartz.JobExecutionException;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.beans.factory.config.ConfigurableBeanFactory;
15 | import org.springframework.context.annotation.Scope;
16 |
17 | import de.chandre.quartz.spring.queue.JobExecutionResult;
18 | import de.chandre.quartz.spring.queue.QueueService;
19 | import de.chandre.quartz.spring.queue.QueuedInstance;
20 |
21 | /**
22 | * simple example of Quartz job
23 | * @author Andre
24 | *
25 | */
26 | @Scope(scopeName=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
27 | public class CallbackQueuedJob implements Job, QueuedInstance
28 | {
29 | private final Log LOGGER = LogFactory.getLog(CallbackQueuedJob.class);
30 |
31 | public static String GROUP = "myGroup";
32 |
33 | @Autowired
34 | private QueueService> queueService;
35 |
36 | private JobExecutionContext context = null;
37 |
38 | @Override
39 | public String getGroup() {
40 | return GROUP;
41 | }
42 |
43 | @Override
44 | public String getName() {
45 | if (null != context) {
46 | return context.getTrigger().getKey().getName();
47 | }
48 | return QueuedInstance.super.getName();
49 | }
50 |
51 | @Override
52 | public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException{
53 | LOGGER.info("start executing callback job: " + jobExecutionContext.getTrigger().getKey().getName());
54 | this.context = jobExecutionContext;
55 | Future future= queueService.queueMe(this);
56 |
57 | try {
58 | if (null != future) {
59 | JobExecutionResult jer = future.get(10000L, TimeUnit.MILLISECONDS);
60 |
61 | if (jer.getException() != null) {
62 | throw new JobExecutionException(jer.getException());
63 | } else {
64 | LOGGER.info("finished callback job with: " + jer.isSuccess() + " of job " + jobExecutionContext.getTrigger().getKey().getName());
65 | }
66 | } else {
67 | LOGGER.info("job not added " + jobExecutionContext.getTrigger().getKey().getName());
68 | }
69 |
70 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
71 | throw new JobExecutionException(e);
72 | }
73 | }
74 |
75 | @Override
76 | public boolean run() {
77 | LOGGER.info("running the " + getClass().getSimpleName() + " with trigger " + context.getTrigger().getKey().getName());
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/jobs/SimpleCronJob.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.jobs;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 | import org.quartz.Job;
6 | import org.quartz.JobExecutionContext;
7 |
8 | /**
9 | * simple example of Quartz job
10 | * @author Andre
11 | *
12 | */
13 | public class SimpleCronJob implements Job
14 | {
15 | private static final Log LOGGER = LogFactory.getLog(SimpleCronJob.class);
16 |
17 | @Override
18 | public void execute(JobExecutionContext jobExecutionContext) {
19 | LOGGER.info("executing cron job: " + jobExecutionContext.getJobDetail().getKey().getName());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/jobs/SimpleJob.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.jobs;
2 |
3 | import org.apache.commons.logging.Log;
4 | import org.apache.commons.logging.LogFactory;
5 | import org.quartz.Job;
6 | import org.quartz.JobExecutionContext;
7 |
8 | /**
9 | * simple example of Quartz job
10 | * @author Andre
11 | *
12 | */
13 | public class SimpleJob implements Job
14 | {
15 | private static final Log LOGGER = LogFactory.getLog(SimpleJob.class);
16 |
17 | @Override
18 | public void execute(JobExecutionContext jobExecutionContext) {
19 | LOGGER.info("start executing job: " + jobExecutionContext.getJobDetail().getKey().getName());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/app/TestApplication.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.app;
2 |
3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 |
7 | @SpringBootApplication
8 | @EnableAutoConfiguration
9 | @ComponentScan(basePackages={"de.chandre.quartz.spring"})
10 | public class TestApplication {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/app/TestApplication2.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.app;
2 |
3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 | import org.springframework.context.annotation.EnableMBeanExport;
7 |
8 | @SpringBootApplication
9 | @EnableAutoConfiguration
10 | @EnableMBeanExport
11 | @ComponentScan(basePackages={"de.chandre.quartz.spring"})
12 | public class TestApplication2 {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig10Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.assertTrue;
6 |
7 | import java.lang.management.ManagementFactory;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Set;
11 |
12 | import javax.management.MBeanServer;
13 | import javax.management.MBeanServerFactory;
14 | import javax.management.ObjectName;
15 |
16 | import org.junit.Test;
17 | import org.junit.runner.RunWith;
18 | import org.quartz.Scheduler;
19 | import org.quartz.SchedulerException;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.boot.test.context.SpringBootTest;
22 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
23 | import org.springframework.test.annotation.DirtiesContext;
24 | import org.springframework.test.context.TestPropertySource;
25 | import org.springframework.test.context.junit4.SpringRunner;
26 |
27 | import de.chandre.quartz.spring.app.TestApplication2;
28 |
29 | /**
30 | * JMX test
31 | * @author André
32 | * @since 1.0.5
33 | *
34 | */
35 | @RunWith(SpringRunner.class)
36 | @SpringBootTest(classes=TestApplication2.class)
37 | @TestPropertySource(properties = {
38 | "quartz.enabled=true",
39 | "quartz.scheduler-factory.scheduler-name=MyTestScheduler",
40 | //"quartz.properties.org.quartz.scheduler.instanceName=MyTestScheduler",
41 | "quartz.properties.org.quartz.scheduler.instanceId=MyTestInstanceId",
42 | "quartz.properties.org.quartz.scheduler.jmx.export=true",
43 | "quartz.metrics.enabled=true",
44 | "flyway.enabled=false",
45 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
46 | "spring.datasource.username=sa",
47 | "spring.datasource.password=",
48 | "spring.datasource.driver-class-name=org.h2.Driver",
49 | "spring.jpa.hibernate.ddl-auto=validate",
50 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
51 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect",
52 | "spring.jmx.enabled=true"
53 | })
54 | @DirtiesContext
55 | public class QuartzSchedulerAutoConfig10Test {
56 |
57 | @Autowired
58 | private Scheduler scheduler;
59 |
60 | @Autowired
61 | private SchedulerFactoryBean schedulerFactory;
62 |
63 | @Test
64 | public void startEnvironment_test() throws SchedulerException {
65 | assertNotNull(scheduler);
66 | assertNotNull(schedulerFactory);
67 |
68 | assertThat( scheduler.getSchedulerName()).isEqualTo("MyTestScheduler");
69 |
70 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("MyTestInstanceId");
71 |
72 | try {
73 | ManagementFactory.getPlatformMBeanServer();
74 | List servers = MBeanServerFactory.findMBeanServer(null);
75 | assertNotNull(servers);
76 | assertThat(servers.size()).isGreaterThan(0);
77 | MBeanServer server = servers.get(0);
78 | List domains = Arrays.asList(server.getDomains());
79 | assertNotNull(domains);
80 | assertThat(domains.size()).isGreaterThan(0);
81 |
82 | String domain = "quartz";
83 | assertThat(domains).contains(domain);
84 |
85 | Set names =server.queryNames(new ObjectName(domain+":*"), null);
86 |
87 | ObjectName name = names.iterator().next();
88 | assertThat(name.toString()).isEqualTo(domain + ":type=QuartzScheduler,name=MyTestScheduler,instance=MyTestInstanceId");
89 |
90 | } catch (Exception e) {
91 | assertTrue(e.getMessage(), false);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig11Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.assertTrue;
6 |
7 | import java.lang.management.ManagementFactory;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.Set;
11 |
12 | import javax.management.MBeanServer;
13 | import javax.management.MBeanServerFactory;
14 | import javax.management.ObjectName;
15 |
16 | import org.junit.Test;
17 | import org.junit.runner.RunWith;
18 | import org.quartz.Scheduler;
19 | import org.quartz.SchedulerException;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.boot.test.context.SpringBootTest;
22 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
23 | import org.springframework.test.annotation.DirtiesContext;
24 | import org.springframework.test.context.ContextConfiguration;
25 | import org.springframework.test.context.TestPropertySource;
26 | import org.springframework.test.context.junit4.SpringRunner;
27 |
28 | import de.chandre.quartz.context.TestContextConfiguration11;
29 | import de.chandre.quartz.jobs.CallbackQueuedJob;
30 | import de.chandre.quartz.spring.app.TestApplication2;
31 | import de.chandre.quartz.spring.queue.QueueService;
32 | import de.chandre.quartz.spring.queue.QueuedInstance;
33 |
34 | /**
35 | * JMX test
36 | * @author André
37 | * @since 1.0.5
38 | *
39 | */
40 | @RunWith(SpringRunner.class)
41 | @SpringBootTest(classes=TestApplication2.class)
42 | @ContextConfiguration(classes= TestContextConfiguration11.class)
43 | @TestPropertySource(properties = {
44 | "quartz.enabled=true",
45 | "quartz.scheduler-factory.scheduler-name=MyTestScheduler",
46 | "quartz.properties.org.quartz.scheduler.instanceId=MyTestInstanceId",
47 | "quartz.properties.org.quartz.scheduler.jmx.export=false",
48 | "quartz.metrics.enabled=true",
49 | "flyway.enabled=false",
50 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
51 | "spring.datasource.username=sa",
52 | "spring.datasource.password=",
53 | "spring.datasource.driver-class-name=org.h2.Driver",
54 | "spring.jpa.hibernate.ddl-auto=validate",
55 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
56 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect",
57 | "spring.jmx.enabled=true"
58 | })
59 | @DirtiesContext
60 | public class QuartzSchedulerAutoConfig11Test {
61 |
62 | @Autowired
63 | private Scheduler scheduler;
64 |
65 | @Autowired
66 | private SchedulerFactoryBean schedulerFactory;
67 |
68 | @Autowired
69 | private QueueService queueService;
70 |
71 | @Test
72 | public void startEnvironment_test() throws SchedulerException {
73 | assertNotNull(scheduler);
74 | assertNotNull(schedulerFactory);
75 |
76 | assertThat( scheduler.getSchedulerName()).isEqualTo("MyTestScheduler");
77 |
78 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("MyTestInstanceId");
79 |
80 | try {
81 | ManagementFactory.getPlatformMBeanServer();
82 | List servers = MBeanServerFactory.findMBeanServer(null);
83 | assertNotNull(servers);
84 | assertThat(servers.size()).isGreaterThan(0);
85 | MBeanServer server = servers.get(0);
86 | List domains = Arrays.asList(server.getDomains());
87 | assertNotNull(domains);
88 | assertThat(domains.size()).isGreaterThan(0);
89 |
90 | String domain = "quartz";
91 | assertThat(domains).doesNotContain(domain);
92 |
93 | //wait a while until some jobs have been triggered
94 | Thread.sleep(1000L);
95 |
96 | assertThat(queueService.getGroups()).containsOnlyOnce(QueuedInstance.DEFAULT_GROUP, CallbackQueuedJob.GROUP);
97 |
98 | } catch (Exception e) {
99 | assertTrue(e.getMessage(), false);
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig1Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.context.TestPropertySource;
14 | import org.springframework.test.context.junit4.SpringRunner;
15 |
16 | import de.chandre.quartz.spring.QuartzSchedulerAutoConfiguration;
17 | import de.chandre.quartz.spring.app.TestApplication;
18 |
19 | @RunWith(SpringRunner.class)
20 | @SpringBootTest(classes=TestApplication.class)
21 | @TestPropertySource(properties = {
22 | "quartz.enabled=true",
23 | "quartz.properties.org.quartz.scheduler.instanceId=MyTestInstanceId",
24 | "flyway.enabled=false",
25 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
26 | "spring.datasource.username=sa",
27 | "spring.datasource.password=",
28 | "spring.datasource.driver-class-name=org.h2.Driver",
29 | "spring.jpa.hibernate.ddl-auto=validate",
30 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
31 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"
32 | })
33 | //@DirtiesContext
34 | public class QuartzSchedulerAutoConfig1Test {
35 |
36 | @Autowired
37 | private Scheduler scheduler;
38 |
39 | @Autowired
40 | private SchedulerFactoryBean schedulerFactory;
41 |
42 | @Test
43 | public void startEnvironment_test() throws SchedulerException {
44 | assertNotNull(scheduler);
45 | assertNotNull(schedulerFactory);
46 |
47 | assertThat( scheduler.getSchedulerName()).isEqualTo(QuartzSchedulerAutoConfiguration.QUARTZ_SCHEDULER_FACTORY_BEAN_NAME);
48 |
49 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("MyTestInstanceId");
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig2Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.junit.Assert.assertNull;
4 |
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
10 | import org.springframework.test.context.TestPropertySource;
11 | import org.springframework.test.context.junit4.SpringRunner;
12 |
13 | import de.chandre.quartz.spring.app.TestApplication;
14 |
15 | @RunWith(SpringRunner.class)
16 | @SpringBootTest(classes=TestApplication.class)
17 | @TestPropertySource(properties = {
18 | "quartz.enabled=false",
19 | "flyway.enabled=false",
20 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
21 | "spring.datasource.username=sa",
22 | "spring.datasource.password=",
23 | "spring.datasource.driver-class-name=org.h2.Driver",
24 | "spring.jpa.hibernate.ddl-auto=validate",
25 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
26 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
27 | //@DirtiesContext
28 | public class QuartzSchedulerAutoConfig2Test {
29 |
30 | @Autowired(required=false)
31 | private SchedulerFactoryBean schedulerFactory;
32 |
33 | @Test
34 | public void startEnvironment_test2() {
35 | assertNull(schedulerFactory);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig3Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.context.ContextConfiguration;
14 | import org.springframework.test.context.TestPropertySource;
15 | import org.springframework.test.context.junit4.SpringRunner;
16 |
17 | import de.chandre.quartz.context.TestContextConfiguration3;
18 | import de.chandre.quartz.spring.QuartzSchedulerProperties;
19 | import de.chandre.quartz.spring.app.TestApplication;
20 |
21 | @RunWith(SpringRunner.class)
22 | @SpringBootTest(classes=TestApplication.class)
23 | @ContextConfiguration(classes= TestContextConfiguration3.class)
24 | @TestPropertySource(properties = {
25 | "quartz.enabled=true",
26 | "quartz.persistence.persisted=true",
27 | "quartz.persistence.use-platform-tx-manager=true",
28 | "quartz.properties-config-location=classpath:differentQuartzScheduler.properties",
29 | "flyway.enabled=true",
30 | "flyway.locations=classpath:db/migration/h2",
31 | "spring.datasource.initialize=true",
32 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
33 | "spring.datasource.username=sa",
34 | "spring.datasource.password=",
35 | "spring.datasource.driver-class-name=org.h2.Driver",
36 | "spring.jpa.hibernate.ddl-auto=validate",
37 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
38 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
39 | //@DirtiesContext
40 | public class QuartzSchedulerAutoConfig3Test {
41 |
42 | @Autowired
43 | private Scheduler scheduler;
44 |
45 | @Autowired
46 | private SchedulerFactoryBean schedulerFactory;
47 |
48 | @Autowired
49 | private QuartzSchedulerProperties props;
50 |
51 | @Test
52 | public void startEnvironment_test3() throws SchedulerException {
53 | assertNotNull(scheduler);
54 | assertNotNull(schedulerFactory);
55 |
56 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("OverriddenQuartzSchedulerTestId");
57 |
58 | assertThat(props.toString()).contains("persisted=true", "usePlatformTxManager=true");
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig4Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.annotation.DirtiesContext;
14 | import org.springframework.test.context.ContextConfiguration;
15 | import org.springframework.test.context.TestPropertySource;
16 | import org.springframework.test.context.junit4.SpringRunner;
17 |
18 | import de.chandre.quartz.context.TestContextConfiguration4;
19 | import de.chandre.quartz.spring.app.TestApplication;
20 |
21 | @RunWith(SpringRunner.class)
22 | @SpringBootTest(classes=TestApplication.class)
23 | @ContextConfiguration(classes= TestContextConfiguration4.class)
24 | @TestPropertySource(properties = {
25 | "quartz.enabled=true",
26 | "quartz.persistence.persisted=false",
27 | "quartz.properties-config-location=classpath:differentQuartzScheduler.properties",
28 | "flyway.enabled=true",
29 | "flyway.locations=classpath:db/migration/h2",
30 | "spring.datasource.initialize=true",
31 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
32 | "spring.datasource.username=sa",
33 | "spring.datasource.password=",
34 | "spring.datasource.driver-class-name=org.h2.Driver",
35 | "spring.jpa.hibernate.ddl-auto=validate",
36 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
37 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
38 | @DirtiesContext
39 | public class QuartzSchedulerAutoConfig4Test {
40 |
41 | @Autowired
42 | private Scheduler scheduler;
43 |
44 | @Autowired
45 | private SchedulerFactoryBean schedulerFactory;
46 |
47 | @Test
48 | public void startEnvironment_test4() throws SchedulerException {
49 | assertNotNull(scheduler);
50 | assertNotNull(schedulerFactory);
51 |
52 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("QuartzSchedulerTestId");
53 |
54 | assertThat(scheduler.getJobGroupNames()).containsExactlyInAnyOrder(
55 | TestContextConfiguration4.SIMPLE_JOB_GROUP, TestContextConfiguration4.CRON_JOB_GROUP);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig5Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.BeforeClass;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.quartz.Scheduler;
10 | import org.quartz.SchedulerException;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.test.context.SpringBootTest;
13 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
14 | import org.springframework.test.annotation.DirtiesContext;
15 | import org.springframework.test.context.ContextConfiguration;
16 | import org.springframework.test.context.TestPropertySource;
17 | import org.springframework.test.context.junit4.SpringRunner;
18 |
19 | import de.chandre.quartz.context.StaticLog;
20 | import de.chandre.quartz.context.TestContextConfiguration5;
21 | import de.chandre.quartz.spring.app.TestApplication;
22 |
23 | /**
24 | *
25 | * @author André Hertwig
26 | * @since 1.0.1
27 | */
28 | @RunWith(SpringRunner.class)
29 | @SpringBootTest(classes=TestApplication.class)
30 | @ContextConfiguration(classes= TestContextConfiguration5.class)
31 | @TestPropertySource(properties = {
32 | "quartz.enabled=true",
33 | "quartz.persistence.persisted=false",
34 | "quartz.override-config-location-properties=false",
35 | "quartz.properties-config-location=classpath:differentQuartzScheduler.properties",
36 | "flyway.enabled=true",
37 | "flyway.locations=classpath:db/migration/h2",
38 | "spring.datasource.initialize=true",
39 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
40 | "spring.datasource.username=sa",
41 | "spring.datasource.password=",
42 | "spring.datasource.driver-class-name=org.h2.Driver",
43 | "spring.jpa.hibernate.ddl-auto=validate",
44 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
45 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect",
46 | "logging.level.=error",
47 | "spring.main.banner-mode=off"})
48 | @DirtiesContext
49 | public class QuartzSchedulerAutoConfig5Test {
50 |
51 | @Autowired
52 | private Scheduler scheduler;
53 |
54 | @Autowired
55 | private SchedulerFactoryBean schedulerFactory;
56 |
57 | @BeforeClass
58 | public static void clear() {
59 | StaticLog.getInstance().clear();
60 | }
61 |
62 | @Test
63 | public void startEnvironment_test5() throws SchedulerException {
64 | assertNotNull(scheduler);
65 | assertNotNull(schedulerFactory);
66 |
67 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("QuartzSchedulerTestId");
68 |
69 | assertThat(StaticLog.getInstance().getMessasges()).containsExactlyInAnyOrder(
70 | TestContextConfiguration5.CAPTURE1,TestContextConfiguration5.CAPTURE2 );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig6Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.context.ContextConfiguration;
14 | import org.springframework.test.context.TestPropertySource;
15 | import org.springframework.test.context.junit4.SpringRunner;
16 |
17 | import de.chandre.quartz.context.TestContextConfiguration4;
18 | import de.chandre.quartz.spring.QuartzSchedulerProperties;
19 | import de.chandre.quartz.spring.app.TestApplication;
20 |
21 | /**
22 | *
23 | * @author André Hertwig
24 | * @since 1.0.1
25 | */
26 | @RunWith(SpringRunner.class)
27 | @SpringBootTest(classes=TestApplication.class)
28 | @ContextConfiguration(classes= TestContextConfiguration4.class)
29 | @TestPropertySource(properties = {
30 | "quartz.enabled=true",
31 | "quartz.persistence.persisted=false",
32 | "quartz.override-config-location-properties=false",
33 | "quartz.properties-config-location=classpath:differentQuartzScheduler.properties",
34 | "quartz.properties.org.quartz.scheduler.instanceId=OnlyAppPropertyTestId",
35 | "quartz.scheduler-factory.scheduler-name=MySpecialScheduler",
36 | "quartz.scheduler-factory.auto-startup=false",
37 | "quartz.scheduler-factory.wait-for-jobs-to-complete-on-shutdown=true",
38 | "quartz.scheduler-factory.overwrite-existing-jobs=true",
39 | "quartz.scheduler-factory.expose-scheduler-in-repository=true",
40 | "quartz.scheduler-factory.phase=12345",
41 | "quartz.scheduler-factory.startup-delay=3000",
42 | "flyway.enabled=true",
43 | "flyway.locations=classpath:db/migration/h2",
44 | "spring.datasource.initialize=true",
45 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
46 | "spring.datasource.username=sa",
47 | "spring.datasource.password=",
48 | "spring.datasource.driver-class-name=org.h2.Driver",
49 | "spring.jpa.hibernate.ddl-auto=validate",
50 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
51 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
52 | //@DirtiesContext
53 | public class QuartzSchedulerAutoConfig6Test {
54 |
55 | @Autowired
56 | private Scheduler scheduler;
57 |
58 | @Autowired
59 | private SchedulerFactoryBean schedulerFactory;
60 |
61 | @Autowired
62 | private QuartzSchedulerProperties props;
63 |
64 | @Test
65 | public void startEnvironment_test6() throws SchedulerException {
66 | assertNotNull(scheduler);
67 | assertNotNull(schedulerFactory);
68 |
69 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("OnlyAppPropertyTestId");
70 |
71 | assertThat(scheduler.getJobGroupNames()).containsExactlyInAnyOrder(
72 | TestContextConfiguration4.SIMPLE_JOB_GROUP, TestContextConfiguration4.CRON_JOB_GROUP);
73 |
74 | assertThat(props.toString()).contains("schedulerName=MySpecialScheduler", "autoStartup=false",
75 | "waitForJobsToCompleteOnShutdown=true", "overwriteExistingJobs=true",
76 | "exposeSchedulerInRepository=true", "phase=12345", "startupDelay=3000");
77 |
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig7Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.context.ContextConfiguration;
14 | import org.springframework.test.context.TestPropertySource;
15 | import org.springframework.test.context.junit4.SpringRunner;
16 |
17 | import de.chandre.quartz.context.TestContextConfiguration7;
18 | import de.chandre.quartz.spring.app.TestApplication;
19 |
20 | /**
21 | *
22 | * @author André Hertwig
23 | * @since 1.0.1
24 | */
25 | @RunWith(SpringRunner.class)
26 | @SpringBootTest(classes=TestApplication.class)
27 | @ContextConfiguration(classes= TestContextConfiguration7.class)
28 | @TestPropertySource(properties = {
29 | "quartz.enabled=true",
30 | "quartz.persistence.persisted=true",
31 | "quartz.persistence.data-source-name=otherDataSource",
32 | "quartz.properties-config-location=classpath:overriddenQuartzScheduler.properties",
33 | "flyway.enabled=false",
34 | "flyway.locations=classpath:db/migration/h2",
35 | "spring.datasource.initialize=true",
36 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
37 | "spring.datasource.username=sa",
38 | "spring.datasource.password=",
39 | "spring.datasource.driver-class-name=org.h2.Driver",
40 | "spring.jpa.hibernate.ddl-auto=validate",
41 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
42 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
43 | //@DirtiesContext
44 | public class QuartzSchedulerAutoConfig7Test {
45 |
46 | @Autowired
47 | private Scheduler scheduler;
48 |
49 | @Autowired
50 | private SchedulerFactoryBean schedulerFactory;
51 |
52 | @Test
53 | public void startEnvironment_test7() throws SchedulerException {
54 | assertNotNull(scheduler);
55 | assertNotNull(schedulerFactory);
56 |
57 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("OverriddenQuartzSchedulerTestId");
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig8Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.quartz.Scheduler;
9 | import org.quartz.SchedulerException;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
13 | import org.springframework.test.context.ContextConfiguration;
14 | import org.springframework.test.context.TestPropertySource;
15 | import org.springframework.test.context.junit4.SpringRunner;
16 |
17 | import de.chandre.quartz.context.TestContextConfiguration8;
18 | import de.chandre.quartz.spring.app.TestApplication;
19 |
20 | /**
21 | *
22 | * @author André Hertwig
23 | * @since 1.0.1
24 | */
25 | @RunWith(SpringRunner.class)
26 | @SpringBootTest(classes=TestApplication.class)
27 | @ContextConfiguration(classes= TestContextConfiguration8.class)
28 | @TestPropertySource(properties = {
29 | "quartz.enabled=true",
30 | "quartz.persistence.persisted=true",
31 | "quartz.persistence.platform-tx-manager-bean-name=secondTransactionManager",
32 | "quartz.properties-config-location=classpath:overriddenQuartzScheduler.properties",
33 | "flyway.enabled=true",
34 | "flyway.locations=classpath:db/migration/h2",
35 | "spring.datasource.initialize=true",
36 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
37 | "spring.datasource.username=sa",
38 | "spring.datasource.password=",
39 | "spring.datasource.driver-class-name=org.h2.Driver",
40 | "spring.jpa.hibernate.ddl-auto=validate",
41 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
42 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect"})
43 | public class QuartzSchedulerAutoConfig8Test {
44 |
45 | @Autowired
46 | private Scheduler scheduler;
47 |
48 | @Autowired
49 | private SchedulerFactoryBean schedulerFactory;
50 |
51 | @Test
52 | public void startEnvironment_test8() throws SchedulerException {
53 | assertNotNull(scheduler);
54 | assertNotNull(schedulerFactory);
55 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("OverriddenQuartzSchedulerTestId");
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/de/chandre/quartz/spring/test/QuartzSchedulerAutoConfig9Test.java:
--------------------------------------------------------------------------------
1 | package de.chandre.quartz.spring.test;
2 |
3 | import static org.assertj.core.api.Assertions.assertThat;
4 | import static org.junit.Assert.assertNotNull;
5 |
6 | import org.junit.BeforeClass;
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 | import org.quartz.Scheduler;
10 | import org.quartz.SchedulerException;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.test.context.SpringBootTest;
13 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
14 | import org.springframework.test.context.ContextConfiguration;
15 | import org.springframework.test.context.TestPropertySource;
16 | import org.springframework.test.context.junit4.SpringRunner;
17 |
18 | import de.chandre.quartz.context.StaticLog;
19 | import de.chandre.quartz.context.TestContextConfiguration9;
20 | import de.chandre.quartz.spring.app.TestApplication;
21 |
22 | /**
23 | *
24 | * @author André Hertwig
25 | * @since 1.0.1
26 | */
27 | @RunWith(SpringRunner.class)
28 | @SpringBootTest(classes=TestApplication.class)
29 | @ContextConfiguration(classes= TestContextConfiguration9.class)
30 | @TestPropertySource(properties = {
31 | "quartz.enabled=true",
32 | "quartz.persistence.persisted=false",
33 | "quartz.override-config-location-properties=false",
34 | //"quartz.properties.org.quartz.threadPool.class=org.springframework.scheduling.quartz.LocalTaskExecutorThreadPool",
35 | "quartz.properties.org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore",
36 | "quartz.properties.org.quartz.jobStore.misfireThreshold=60000",
37 | "quartz.properties.org.quartz.scheduler.skipUpdateCheck=true",
38 |
39 | "flyway.enabled=true",
40 | "flyway.locations=classpath:db/migration/h2",
41 | "spring.datasource.initialize=true",
42 | "spring.datasource.url=jdbc:h2:mem:datajpa;MODE=Oracle",
43 | "spring.datasource.username=sa",
44 | "spring.datasource.password=",
45 | "spring.datasource.driver-class-name=org.h2.Driver",
46 | "spring.jpa.hibernate.ddl-auto=validate",
47 | "spring.jpa.database-platform=org.hibernate.dialect.H2Dialect",
48 | "spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect",
49 | "logging.level.=error",
50 | "spring.main.banner-mode=off"})
51 | public class QuartzSchedulerAutoConfig9Test {
52 |
53 | @Autowired
54 | private Scheduler scheduler;
55 |
56 | @Autowired
57 | private SchedulerFactoryBean schedulerFactory;
58 |
59 | @BeforeClass
60 | public static void clear() {
61 | StaticLog.getInstance().clear();
62 | }
63 |
64 | @Test
65 | public void startEnvironment_test5() throws SchedulerException {
66 | assertNotNull(scheduler);
67 | assertNotNull(schedulerFactory);
68 |
69 | assertThat(scheduler.getSchedulerInstanceId()).isEqualTo("NON_CLUSTERED");
70 |
71 | assertThat(StaticLog.getInstance().getMessasges()).containsExactlyInAnyOrder(
72 | TestContextConfiguration9.CAPTURE1);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/resources/db/migration/h2/V001__QuartzInitialization.sql:
--------------------------------------------------------------------------------
1 | -- Thanks to Amir Kibbar and Peter Rietzler for contributing the schema for H2 database,
2 | -- and verifying that it works with Quartz's StdJDBCDelegate
3 | --
4 | -- Note, Quartz depends on row-level locking which means you must use the MVCC=TRUE
5 | -- setting on your H2 database, or you will experience dead-locks
6 | --
7 | --
8 | -- In your Quartz properties file, you'll need to set
9 | -- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
10 |
11 | CREATE TABLE QRTZ_CALENDARS (
12 | SCHED_NAME VARCHAR(120) NOT NULL,
13 | CALENDAR_NAME VARCHAR (200) NOT NULL ,
14 | CALENDAR IMAGE NOT NULL
15 | );
16 |
17 | CREATE TABLE QRTZ_CRON_TRIGGERS (
18 | SCHED_NAME VARCHAR(120) NOT NULL,
19 | TRIGGER_NAME VARCHAR (200) NOT NULL ,
20 | TRIGGER_GROUP VARCHAR (200) NOT NULL ,
21 | CRON_EXPRESSION VARCHAR (120) NOT NULL ,
22 | TIME_ZONE_ID VARCHAR (80)
23 | );
24 |
25 | CREATE TABLE QRTZ_FIRED_TRIGGERS (
26 | SCHED_NAME VARCHAR(120) NOT NULL,
27 | ENTRY_ID VARCHAR (95) NOT NULL ,
28 | TRIGGER_NAME VARCHAR (200) NOT NULL ,
29 | TRIGGER_GROUP VARCHAR (200) NOT NULL ,
30 | INSTANCE_NAME VARCHAR (200) NOT NULL ,
31 | FIRED_TIME BIGINT NOT NULL ,
32 | SCHED_TIME BIGINT NOT NULL ,
33 | PRIORITY INTEGER NOT NULL ,
34 | STATE VARCHAR (16) NOT NULL,
35 | JOB_NAME VARCHAR (200) NULL ,
36 | JOB_GROUP VARCHAR (200) NULL ,
37 | IS_NONCONCURRENT BOOLEAN NULL ,
38 | REQUESTS_RECOVERY BOOLEAN NULL
39 | );
40 |
41 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
42 | SCHED_NAME VARCHAR(120) NOT NULL,
43 | TRIGGER_GROUP VARCHAR (200) NOT NULL
44 | );
45 |
46 | CREATE TABLE QRTZ_SCHEDULER_STATE (
47 | SCHED_NAME VARCHAR(120) NOT NULL,
48 | INSTANCE_NAME VARCHAR (200) NOT NULL ,
49 | LAST_CHECKIN_TIME BIGINT NOT NULL ,
50 | CHECKIN_INTERVAL BIGINT NOT NULL
51 | );
52 |
53 | CREATE TABLE QRTZ_LOCKS (
54 | SCHED_NAME VARCHAR(120) NOT NULL,
55 | LOCK_NAME VARCHAR (40) NOT NULL
56 | );
57 |
58 | CREATE TABLE QRTZ_JOB_DETAILS (
59 | SCHED_NAME VARCHAR(120) NOT NULL,
60 | JOB_NAME VARCHAR (200) NOT NULL ,
61 | JOB_GROUP VARCHAR (200) NOT NULL ,
62 | DESCRIPTION VARCHAR (250) NULL ,
63 | JOB_CLASS_NAME VARCHAR (250) NOT NULL ,
64 | IS_DURABLE BOOLEAN NOT NULL ,
65 | IS_NONCONCURRENT BOOLEAN NOT NULL ,
66 | IS_UPDATE_DATA BOOLEAN NOT NULL ,
67 | REQUESTS_RECOVERY BOOLEAN NOT NULL ,
68 | JOB_DATA IMAGE NULL
69 | );
70 |
71 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
72 | SCHED_NAME VARCHAR(120) NOT NULL,
73 | TRIGGER_NAME VARCHAR (200) NOT NULL ,
74 | TRIGGER_GROUP VARCHAR (200) NOT NULL ,
75 | REPEAT_COUNT BIGINT NOT NULL ,
76 | REPEAT_INTERVAL BIGINT NOT NULL ,
77 | TIMES_TRIGGERED BIGINT NOT NULL
78 | );
79 |
80 | CREATE TABLE QRTZ_simprop_triggers
81 | (
82 | SCHED_NAME VARCHAR(120) NOT NULL,
83 | TRIGGER_NAME VARCHAR(200) NOT NULL,
84 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
85 | STR_PROP_1 VARCHAR(512) NULL,
86 | STR_PROP_2 VARCHAR(512) NULL,
87 | STR_PROP_3 VARCHAR(512) NULL,
88 | INT_PROP_1 INTEGER NULL,
89 | INT_PROP_2 INTEGER NULL,
90 | LONG_PROP_1 BIGINT NULL,
91 | LONG_PROP_2 BIGINT NULL,
92 | DEC_PROP_1 NUMERIC(13,4) NULL,
93 | DEC_PROP_2 NUMERIC(13,4) NULL,
94 | BOOL_PROP_1 BOOLEAN NULL,
95 | BOOL_PROP_2 BOOLEAN NULL,
96 | );
97 |
98 | CREATE TABLE QRTZ_BLOB_TRIGGERS (
99 | SCHED_NAME VARCHAR(120) NOT NULL,
100 | TRIGGER_NAME VARCHAR (200) NOT NULL ,
101 | TRIGGER_GROUP VARCHAR (200) NOT NULL ,
102 | BLOB_DATA IMAGE NULL
103 | );
104 |
105 | CREATE TABLE QRTZ_TRIGGERS (
106 | SCHED_NAME VARCHAR(120) NOT NULL,
107 | TRIGGER_NAME VARCHAR (200) NOT NULL ,
108 | TRIGGER_GROUP VARCHAR (200) NOT NULL ,
109 | JOB_NAME VARCHAR (200) NOT NULL ,
110 | JOB_GROUP VARCHAR (200) NOT NULL ,
111 | DESCRIPTION VARCHAR (250) NULL ,
112 | NEXT_FIRE_TIME BIGINT NULL ,
113 | PREV_FIRE_TIME BIGINT NULL ,
114 | PRIORITY INTEGER NULL ,
115 | TRIGGER_STATE VARCHAR (16) NOT NULL ,
116 | TRIGGER_TYPE VARCHAR (8) NOT NULL ,
117 | START_TIME BIGINT NOT NULL ,
118 | END_TIME BIGINT NULL ,
119 | CALENDAR_NAME VARCHAR (200) NULL ,
120 | MISFIRE_INSTR SMALLINT NULL ,
121 | JOB_DATA IMAGE NULL
122 | );
123 |
124 | ALTER TABLE QRTZ_CALENDARS ADD
125 | CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY
126 | (
127 | SCHED_NAME,
128 | CALENDAR_NAME
129 | );
130 |
131 | ALTER TABLE QRTZ_CRON_TRIGGERS ADD
132 | CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY
133 | (
134 | SCHED_NAME,
135 | TRIGGER_NAME,
136 | TRIGGER_GROUP
137 | );
138 |
139 | ALTER TABLE QRTZ_FIRED_TRIGGERS ADD
140 | CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY
141 | (
142 | SCHED_NAME,
143 | ENTRY_ID
144 | );
145 |
146 | ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD
147 | CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY
148 | (
149 | SCHED_NAME,
150 | TRIGGER_GROUP
151 | );
152 |
153 | ALTER TABLE QRTZ_SCHEDULER_STATE ADD
154 | CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY
155 | (
156 | SCHED_NAME,
157 | INSTANCE_NAME
158 | );
159 |
160 | ALTER TABLE QRTZ_LOCKS ADD
161 | CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY
162 | (
163 | SCHED_NAME,
164 | LOCK_NAME
165 | );
166 |
167 | ALTER TABLE QRTZ_JOB_DETAILS ADD
168 | CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY
169 | (
170 | SCHED_NAME,
171 | JOB_NAME,
172 | JOB_GROUP
173 | );
174 |
175 | ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD
176 | CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY
177 | (
178 | SCHED_NAME,
179 | TRIGGER_NAME,
180 | TRIGGER_GROUP
181 | );
182 |
183 | ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD
184 | CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY
185 | (
186 | SCHED_NAME,
187 | TRIGGER_NAME,
188 | TRIGGER_GROUP
189 | );
190 |
191 | ALTER TABLE QRTZ_TRIGGERS ADD
192 | CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY
193 | (
194 | SCHED_NAME,
195 | TRIGGER_NAME,
196 | TRIGGER_GROUP
197 | );
198 |
199 | ALTER TABLE QRTZ_CRON_TRIGGERS ADD
200 | CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
201 | (
202 | SCHED_NAME,
203 | TRIGGER_NAME,
204 | TRIGGER_GROUP
205 | ) REFERENCES QRTZ_TRIGGERS (
206 | SCHED_NAME,
207 | TRIGGER_NAME,
208 | TRIGGER_GROUP
209 | ) ON DELETE CASCADE;
210 |
211 |
212 | ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD
213 | CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
214 | (
215 | SCHED_NAME,
216 | TRIGGER_NAME,
217 | TRIGGER_GROUP
218 | ) REFERENCES QRTZ_TRIGGERS (
219 | SCHED_NAME,
220 | TRIGGER_NAME,
221 | TRIGGER_GROUP
222 | ) ON DELETE CASCADE;
223 |
224 | ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD
225 | CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY
226 | (
227 | SCHED_NAME,
228 | TRIGGER_NAME,
229 | TRIGGER_GROUP
230 | ) REFERENCES QRTZ_TRIGGERS (
231 | SCHED_NAME,
232 | TRIGGER_NAME,
233 | TRIGGER_GROUP
234 | ) ON DELETE CASCADE;
235 |
236 |
237 | ALTER TABLE QRTZ_TRIGGERS ADD
238 | CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY
239 | (
240 | SCHED_NAME,
241 | JOB_NAME,
242 | JOB_GROUP
243 | ) REFERENCES QRTZ_JOB_DETAILS (
244 | SCHED_NAME,
245 | JOB_NAME,
246 | JOB_GROUP
247 | );
248 |
249 | COMMIT;
250 |
--------------------------------------------------------------------------------
/src/test/resources/differentQuartzScheduler.properties:
--------------------------------------------------------------------------------
1 | org.quartz.scheduler.instanceName=QuartzSchedulerTest-Name
2 | org.quartz.scheduler.instanceId=QuartzSchedulerTestId
3 | org.quartz.threadPool.threadCount=5
4 | org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
5 | #org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
6 | #org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore
7 | #org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
8 | #org.quartz.jobStore.useProperties=true
9 | org.quartz.jobStore.misfireThreshold=60000
10 | #org.quartz.jobStore.tablePrefix=QRTZ_
11 |
12 | #org.quartz.jobStore.isClustered=true
13 | #org.quartz.jobStore.clusterCheckinInterval=20000
14 |
15 | org.quartz.scheduler.skipUpdateCheck=true
--------------------------------------------------------------------------------
/src/test/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/test/resources/overriddenQuartzScheduler.properties:
--------------------------------------------------------------------------------
1 | org.quartz.scheduler.instanceName=OverriddenQuartzSchedulerTest-Name
2 | org.quartz.scheduler.instanceId=OverriddenQuartzSchedulerTestId
3 | org.quartz.threadPool.threadCount=5
4 | #org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
5 | org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore
6 | org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
7 | org.quartz.jobStore.useProperties=true
8 | org.quartz.jobStore.misfireThreshold=60000
9 | org.quartz.jobStore.tablePrefix=QRTZ_
10 |
11 | org.quartz.jobStore.isClustered=true
12 | org.quartz.jobStore.clusterCheckinInterval=20000
13 |
14 | org.quartz.scheduler.skipUpdateCheck=true
--------------------------------------------------------------------------------