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

openmrs / openmrs-core / 29845974054

21 Jul 2026 03:51PM UTC coverage: 66.106% (-0.004%) from 66.11%
29845974054

push

github

web-flow
TRUNK-6713: Switch to saner DaemonThread protection scheme (#6361)

60 of 90 new or added lines in 6 files covered. (66.67%)

6 existing lines in 4 files now uncovered.

24347 of 36830 relevant lines covered (66.11%)

0.66 hits per line

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

56.76
/api/src/main/java/org/openmrs/scheduler/timer/TimerSchedulerTask.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.scheduler.timer;
11

12
import java.util.Date;
13
import java.util.TimerTask;
14
import java.util.concurrent.ExecutionException;
15

16
import org.openmrs.api.context.Context;
17
import org.openmrs.api.context.Daemon;
18
import org.openmrs.scheduler.SchedulerService;
19
import org.openmrs.scheduler.SchedulerUtil;
20
import org.openmrs.scheduler.Task;
21
import org.openmrs.scheduler.TaskDefinition;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24

25
public class TimerSchedulerTask extends TimerTask {
26
        
27
        /** The task that will be executed by the JDK timer. */
28
        private Task task;
29
        
30
        /** Logger */
31
        private static final Logger log = LoggerFactory.getLogger(TimerSchedulerTask.class);
1✔
32

33
        /**
34
         * The capability that proves to {@link Daemon} this class is allowed to act with daemon
35
     * permissions.
36
         */
37
        private static volatile Daemon.CallerKey daemonCallerKey;
38

39
        /** * Public constructor */
40
        public TimerSchedulerTask(Task task) {
1✔
41
                this.task = task;
1✔
42
        }
1✔
43
        
44
        /**
45
         * * Executes the action to be performed by this timer task.
46
         * 
47
         * @see java.util.TimerTask#run()
48
         */
49
        @Override
50
        public void run() {
51
                try {
52
                        Daemon.executeScheduledTask(task, daemonCallerKey());
1✔
53
                }
54
                catch (Exception t) {
×
55
                        // Fix #862: IllegalStateException: Timer already cancelled.
56
                        // Suppress error in order to keep the scheduler's Timer from completely failing.
57
                        log.error(
×
58
                            "FATAL ERROR: Task [" + task.getClass() + "] failed due to exception [" + t.getClass().getName() + "]", t);
×
59
                        SchedulerUtil.sendSchedulerError(t);
×
60
                }
1✔
61
        }
1✔
62
        
63
        /**
64
         * Save the last execution time in the TaskDefinition
65
         */
66
        private static void saveLastExecutionTime(Task task) {
67
                TaskDefinition taskDefinition;
68
                try {
69
                        // We re-get the task definition in case the copy set during the
70
                        // task initialization has become stale.  NOTE: If a task does not
71
                        // extend the abstract class AbstractTask, then it's possible the
72
                        // developer did not actually set the TaskDefintion on the Task.
73
                        // Therefore we might get an NPE below.
74
                        if (task.getTaskDefinition() != null) {
1✔
75
                                SchedulerService schedulerService = Context.getSchedulerService();
×
76
                                taskDefinition = task.getTaskDefinition();
×
77
                                taskDefinition.setLastExecutionTime(new Date());
×
78
                                schedulerService.saveTaskDefinition(taskDefinition);
×
79
                        } else {
×
80
                                log.warn("Unable to save the last execution time for task. Task.taskDefinition is null in "
1✔
81
                                        + task.getClass());
1✔
82
                        }
83
                }
84
                catch (Exception e) {
×
85
                        log.warn("Unable to save the last execution time for task ", e);
×
86
                }
1✔
87
        }
1✔
88
        
89
        /**
90
         * Shutdown the timer task and invoke the task's shutdown() callback method.
91
         */
92
        public void shutdown() {
93
                super.cancel();
×
94
                task.shutdown();
×
95
        }
×
96
        
97
        /**
98
         * Executes the given task.
99
         */
100
        public static void execute(Task task) {
101
                try {
102
                        task.execute();
1✔
103
                } catch (InterruptedException | ExecutionException e) {
×
104
                        // ignored
105
                }
1✔
106
                saveLastExecutionTime(task);
1✔
107
        }
1✔
108

109
        /**
110
         * Receives the {@link Daemon} caller key. Called only by {@link Daemon} during its initialization.
111
         *
112
         * @param callerKey the caller key issued by {@link Daemon}
113
         * @since 3.0.0, 2.9.0, 2.8.9
114
         */
115
        public static void setDaemonCallerKey(Daemon.CallerKey callerKey) {
116
                if (callerKey != null && daemonCallerKey == null) {
1✔
117
                        daemonCallerKey = callerKey;
1✔
118
                }
119
        }
1✔
120

121
        /**
122
         * @return the {@link Daemon} caller key. Protected so that {@link TimerSchedulerTask} subclasses,
123
         *         which the old caller check also permitted, can present it when running scheduled tasks.
124
         */
125
        protected static Daemon.CallerKey daemonCallerKey() {
126
                if (daemonCallerKey == null) {
1✔
127
                        // Guarantee Daemon has initialized and therefore handed us the key, regardless of the order in
128
                        // which the two classes were first loaded.
NEW
129
                        Daemon.ensureInitialized();
×
130
                }
131
                return daemonCallerKey;
1✔
132
        }
133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc