• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aspectran / aspectran / #4058

12 Feb 2025 06:52AM CUT coverage: 35.281% (+0.01%) from 35.269%
#4058

push

github

topframe
Update

0 of 2 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

14251 of 40393 relevant lines covered (35.28%)

0.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/core/src/main/java/com/aspectran/core/scheduler/service/AbstractSchedulerService.java
1
/*
2
 * Copyright (c) 2008-2025 The Aspectran Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.aspectran.core.scheduler.service;
17

18
import com.aspectran.core.component.schedule.ScheduleRuleRegistry;
19
import com.aspectran.core.context.ActivityContext;
20
import com.aspectran.core.context.config.AcceptableConfig;
21
import com.aspectran.core.context.config.SchedulerConfig;
22
import com.aspectran.core.context.rule.ScheduleRule;
23
import com.aspectran.core.context.rule.ScheduledJobRule;
24
import com.aspectran.core.context.rule.params.TriggerExpressionParameters;
25
import com.aspectran.core.context.rule.type.TriggerType;
26
import com.aspectran.core.service.AbstractServiceLifeCycle;
27
import com.aspectran.core.service.CoreService;
28
import com.aspectran.core.service.RequestAcceptor;
29
import com.aspectran.utils.Assert;
30
import com.aspectran.utils.annotation.jsr305.NonNull;
31
import com.aspectran.utils.logging.Logger;
32
import com.aspectran.utils.logging.LoggerFactory;
33
import org.quartz.CronScheduleBuilder;
34
import org.quartz.JobBuilder;
35
import org.quartz.JobDataMap;
36
import org.quartz.JobDetail;
37
import org.quartz.JobListener;
38
import org.quartz.Scheduler;
39
import org.quartz.SchedulerException;
40
import org.quartz.SimpleScheduleBuilder;
41
import org.quartz.Trigger;
42
import org.quartz.TriggerBuilder;
43

44
import java.util.Collection;
45
import java.util.Date;
46
import java.util.HashMap;
47
import java.util.List;
48
import java.util.Map;
49

50
/**
51
 * The Class AbstractSchedulerService.
52
 */
53
public abstract class AbstractSchedulerService extends AbstractServiceLifeCycle implements SchedulerService {
54

55
    private static final Logger logger = LoggerFactory.getLogger(AbstractSchedulerService.class);
×
56

57
    private final Map<String, Scheduler> schedulerMap = new HashMap<>();
×
58

59
    private int startDelaySeconds = 0;
×
60

61
    private boolean waitOnShutdown = false;
×
62

63
    private RequestAcceptor requestAcceptor;
64

65
    AbstractSchedulerService(CoreService parentService) {
66
        super(parentService);
×
67
        Assert.notNull(parentService, "parentService must not be null");
×
68
    }
×
69

70
    @Override
71
    public ActivityContext getActivityContext() {
72
        Assert.state(getParentService().getActivityContext() != null,
×
73
                "No ActivityContext configured yet");
74
        return getParentService().getActivityContext();
×
75
    }
76

77
    @Override
78
    public int getStartDelaySeconds() {
79
        return startDelaySeconds;
×
80
    }
81

82
    public void setStartDelaySeconds(int startDelaySeconds) {
83
        this.startDelaySeconds = startDelaySeconds;
×
84
    }
×
85

86
    @Override
87
    public boolean isWaitOnShutdown() {
88
        return waitOnShutdown;
×
89
    }
90

91
    public void setWaitOnShutdown(boolean waitOnShutdown) {
92
        this.waitOnShutdown = waitOnShutdown;
×
93
    }
×
94

95
    @Override
96
    public boolean isDerived() {
97
        return true;
×
98
    }
99

100
    public boolean isAcceptable(String requestName) {
101
        return (requestAcceptor == null || requestAcceptor.isAcceptable(requestName));
×
102
    }
103

104
    protected void setRequestAcceptor(RequestAcceptor requestAcceptor) {
105
        this.requestAcceptor = requestAcceptor;
×
106
    }
×
107

108
    protected Collection<Scheduler> getSchedulers() {
NEW
109
        return schedulerMap.values();
×
110
    }
111

112
    protected Scheduler getScheduler(String scheduleId) {
113
        return schedulerMap.get(scheduleId);
×
114
    }
115

116
    private void addScheduler(String scheduleId, Scheduler scheduler) {
NEW
117
        Assert.notNull(scheduleId, "scheduleId must not be null");
×
118
        Assert.notNull(scheduler, "scheduler must not be null");
×
119
        schedulerMap.put(scheduleId, scheduler);
×
120
    }
×
121

122
    private void clearSchedulers() {
123
        schedulerMap.clear();
×
124
    }
×
125

126
    @Override
127
    protected void doStart() throws Exception {
128
        try {
129
            buildSchedulers();
×
130
            for (Scheduler scheduler : getSchedulers()) {
×
131
                logger.info("Starting scheduler '" + scheduler.getSchedulerName() + "'");
×
132

133
                // Listener attached to jobKey
134
                JobListener defaultJobListener = new QuartzJobListener();
×
135
                scheduler.getListenerManager().addJobListener(defaultJobListener);
×
136

137
                if (getStartDelaySeconds() > 0) {
×
138
                    scheduler.startDelayed(getStartDelaySeconds());
×
139
                } else {
140
                    scheduler.start();
×
141
                }
142
            }
×
143
        } catch (Exception e) {
×
144
            throw new SchedulerServiceException("Could not start DefaultSchedulerService", e);
×
145
        }
×
146
    }
×
147

148
    @Override
149
    protected void doStop() throws Exception {
150
        try {
151
            for (Scheduler scheduler : getSchedulers()) {
×
152
                if (!scheduler.isShutdown()) {
×
153
                    logger.info("Shutting down the scheduler '" + scheduler.getSchedulerName() +
×
154
                            "' with waitForJobsToComplete=" + isWaitOnShutdown());
×
155
                    scheduler.shutdown(isWaitOnShutdown());
×
156
                }
157
            }
×
158
            clearSchedulers();
×
159
        } catch (Exception e) {
×
160
            throw new SchedulerServiceException("Could not shutdown DefaultSchedulerService", e);
×
161
        }
×
162
    }
×
163

164
    private void buildSchedulers() throws SchedulerServiceException {
165
        ScheduleRuleRegistry scheduleRuleRegistry = getActivityContext().getScheduleRuleRegistry();
×
166
        if (scheduleRuleRegistry == null) {
×
167
            return;
×
168
        }
169

170
        Collection<ScheduleRule> scheduleRules = scheduleRuleRegistry.getScheduleRules();
×
171
        if (scheduleRules == null || scheduleRules.isEmpty()) {
×
172
            return;
×
173
        }
174

175
        try {
176
            for (ScheduleRule scheduleRule : scheduleRules) {
×
177
                Scheduler scheduler = createScheduler(scheduleRule);
×
178
                addScheduler(scheduleRule.getId(), scheduler);
×
179
            }
×
180
        } catch (Exception e) {
×
181
            throw new SchedulerServiceException("Could not start DefaultSchedulerService", e);
×
182
        }
×
183
    }
×
184

185
    @NonNull
186
    private Scheduler createScheduler(@NonNull ScheduleRule scheduleRule) throws SchedulerException {
187
        Scheduler scheduler = null;
×
188
        if (scheduleRule.getSchedulerBeanClass() != null) {
×
189
            scheduler = (Scheduler)getActivityContext().getBeanRegistry().getBean(scheduleRule.getSchedulerBeanClass());
×
190
        } else if (scheduleRule.getSchedulerBeanId() != null) {
×
191
            scheduler = getActivityContext().getBeanRegistry().getBean(scheduleRule.getSchedulerBeanId());
×
192
        }
193
        if (scheduler == null) {
×
194
            throw new SchedulerServiceException("No such scheduler bean; Invalid ScheduleRule " + scheduleRule);
×
195
        }
196

197
        List<ScheduledJobRule> jobRuleList = scheduleRule.getScheduledJobRuleList();
×
198
        for (ScheduledJobRule jobRule : jobRuleList) {
×
199
            if (isAcceptable(jobRule.getTransletName())) {
×
200
                JobDetail jobDetail = createJobDetail(jobRule);
×
201
                if (jobDetail != null) {
×
202
                    String triggerName = jobDetail.getKey().getName();
×
203
                    String triggerGroup = scheduleRule.getId();
×
204
                    Trigger trigger = createTrigger(triggerName, triggerGroup, scheduleRule, getStartDelaySeconds());
×
205
                    scheduler.scheduleJob(jobDetail, trigger);
×
206
                }
207
            } else {
×
208
                logger.warn("Unexposed translet [" + jobRule.getTransletName() + "] in ScheduleRule " + scheduleRule);
×
209
            }
210
        }
×
211

212
        return scheduler;
×
213
    }
214

215
    private JobDetail createJobDetail(@NonNull ScheduledJobRule jobRule) {
216
        String jobName = jobRule.getTransletName();
×
217
        String jobGroup = jobRule.getScheduleRule().getId();
×
218

219
        JobDataMap jobDataMap = new JobDataMap();
×
220
        jobDataMap.put(SERVICE_DATA_KEY, this);
×
221
        jobDataMap.put(JOB_RULE_DATA_KEY, jobRule);
×
222

223
        return JobBuilder.newJob(ActivityLauncherJob.class)
×
224
                .withIdentity(jobName, jobGroup)
×
225
                .setJobData(jobDataMap)
×
226
                .build();
×
227
    }
228

229
    private Trigger createTrigger(String name, String group, @NonNull ScheduleRule scheduleRule, final int startDelaySeconds) {
230
        TriggerExpressionParameters expressionParameters = scheduleRule.getTriggerExpressionParameters();
×
231
        int startDelaySecondsToUse = startDelaySeconds;
×
232
        if (expressionParameters.getStartDelaySeconds() != null) {
×
233
            startDelaySecondsToUse += expressionParameters.getStartDelaySeconds();
×
234
        }
235

236
        Date firstFireTime;
237
        if (startDelaySecondsToUse > 0) {
×
238
            firstFireTime = new Date(System.currentTimeMillis() + (startDelaySecondsToUse * 1000L));
×
239
        } else {
240
            firstFireTime = new Date();
×
241
        }
242

243
        if (scheduleRule.getTriggerType() == TriggerType.SIMPLE) {
×
244
            Long intervalInMilliseconds = expressionParameters.getIntervalInMilliseconds();
×
245
            Integer intervalInSeconds = expressionParameters.getIntervalInSeconds();
×
246
            Integer intervalInMinutes = expressionParameters.getIntervalInMinutes();
×
247
            Integer intervalInHours = expressionParameters.getIntervalInHours();
×
248
            Integer repeatCount = expressionParameters.getRepeatCount();
×
249
            Boolean repeatForever = expressionParameters.getRepeatForever();
×
250

251
            SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule();
×
252
            if (intervalInMilliseconds != null) {
×
253
                builder.withIntervalInMilliseconds(intervalInMilliseconds);
×
254
            }
255
            if (intervalInSeconds != null) {
×
256
                builder.withIntervalInSeconds(intervalInSeconds);
×
257
            }
258
            if (intervalInMinutes != null) {
×
259
                builder.withIntervalInMinutes(intervalInMinutes);
×
260
            }
261
            if (intervalInHours != null) {
×
262
                builder.withIntervalInHours(intervalInHours);
×
263
            }
264
            if (repeatCount != null) {
×
265
                builder.withRepeatCount(repeatCount);
×
266
            }
267
            if (Boolean.TRUE.equals(repeatForever)) {
×
268
                builder.repeatForever();
×
269
            }
270

271
            return TriggerBuilder.newTrigger()
×
272
                    .withIdentity(name, group)
×
273
                    .startAt(firstFireTime)
×
274
                    .withSchedule(builder)
×
275
                    .build();
×
276
        } else {
277
            String expression = expressionParameters.getExpression();
×
278
            CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(expression);
×
279

280
            return TriggerBuilder.newTrigger()
×
281
                    .withIdentity(name, group)
×
282
                    .startAt(firstFireTime)
×
283
                    .withSchedule(cronSchedule)
×
284
                    .build();
×
285
        }
286
    }
287

288
    protected void configure(@NonNull SchedulerConfig schedulerConfig) {
289
        int startDelaySeconds = schedulerConfig.getStartDelaySeconds();
×
290
        if (startDelaySeconds == -1) {
×
291
            startDelaySeconds = 3;
×
292
            if (logger.isDebugEnabled()) {
×
293
                logger.debug("Scheduler option 'startDelaySeconds' is not specified, defaulting to 3 seconds");
×
294
            }
295
        }
296

297
        boolean waitOnShutdown = schedulerConfig.isWaitOnShutdown();
×
298
        if (waitOnShutdown) {
×
299
            setWaitOnShutdown(true);
×
300
        }
301
        setStartDelaySeconds(startDelaySeconds);
×
302

303
        AcceptableConfig acceptableConfig = schedulerConfig.getAcceptableConfig();
×
304
        if (acceptableConfig != null) {
×
305
            setRequestAcceptor(new RequestAcceptor(acceptableConfig));
×
306
        }
307
    }
×
308

309
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc