1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.Date;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.ScheduledExecutorService;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.ScheduledThreadPoolExecutor;
24 import java.util.concurrent.TimeUnit;
25
26 import org.apache.logging.log4j.core.AbstractLifeCycle;
27 import org.apache.logging.log4j.core.util.CronExpression;
28 import org.apache.logging.log4j.core.util.Log4jThreadFactory;
29
30
31
32
33 public class ConfigurationScheduler extends AbstractLifeCycle {
34
35 private static final String SIMPLE_NAME = "Log4j2 " + ConfigurationScheduler.class.getSimpleName();
36 private static final int MAX_SCHEDULED_ITEMS = 5;
37 private ScheduledExecutorService executorService;
38
39 private int scheduledItems = 0;
40
41 @Override
42 public void start() {
43 super.start();
44 if (scheduledItems > 0) {
45 LOGGER.debug("{} starting {} threads", scheduledItems, SIMPLE_NAME);
46 scheduledItems = Math.min(scheduledItems, MAX_SCHEDULED_ITEMS);
47 executorService = new ScheduledThreadPoolExecutor(scheduledItems,
48 Log4jThreadFactory.createDaemonThreadFactory("Scheduled"));
49 } else {
50 LOGGER.debug("{}: No scheduled items", SIMPLE_NAME);
51 }
52 }
53
54 @Override
55 public boolean stop(final long timeout, final TimeUnit timeUnit) {
56 setStopping();
57 if (executorService != null) {
58 LOGGER.debug("{} shutting down threads in {}", SIMPLE_NAME, executorService);
59 executorService.shutdown();
60 }
61 setStopped();
62 return true;
63 }
64
65
66
67
68 public void incrementScheduledItems() {
69 if (!isStarted()) {
70 ++scheduledItems;
71 } else {
72 LOGGER.error("{} attempted to increment scheduled items after start", SIMPLE_NAME);
73 }
74 }
75
76
77
78
79 public void decrementScheduledItems() {
80 if (!isStarted() && scheduledItems > 0) {
81 --scheduledItems;
82 }
83 }
84
85
86
87
88
89
90
91
92
93
94 public <V> ScheduledFuture<V> schedule(final Callable<V> callable, final long delay, final TimeUnit unit) {
95 return executorService.schedule(callable, delay, unit);
96 }
97
98
99
100
101
102
103
104
105
106 public ScheduledFuture<?> schedule(final Runnable command, final long delay, final TimeUnit unit) {
107 return executorService.schedule(command, delay, unit);
108 }
109
110
111
112
113
114
115
116
117 public CronScheduledFuture<?> scheduleWithCron(final CronExpression cronExpression, final Runnable command) {
118 final Date fireDate = cronExpression.getNextValidTimeAfter(new Date());
119 final CronRunnable runnable = new CronRunnable(command, cronExpression);
120 final ScheduledFuture<?> future = schedule(runnable, nextFireInterval(fireDate), TimeUnit.MILLISECONDS);
121 final CronScheduledFuture<?> cronScheduledFuture = new CronScheduledFuture<>(future, fireDate);
122 runnable.setScheduledFuture(cronScheduledFuture);
123 return cronScheduledFuture;
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138 public ScheduledFuture<?> scheduleAtFixedRate(final Runnable command, final long initialDelay, final long period, final TimeUnit unit) {
139 return executorService.scheduleAtFixedRate(command, initialDelay, period, unit);
140 }
141
142
143
144
145
146
147
148
149
150
151
152 public ScheduledFuture<?> scheduleWithFixedDelay(final Runnable command, final long initialDelay, final long delay, final TimeUnit unit) {
153 return executorService.scheduleWithFixedDelay(command, initialDelay, delay, unit);
154 }
155
156 public long nextFireInterval(final Date fireDate) {
157 return fireDate.getTime() - new Date().getTime();
158 }
159
160 public class CronRunnable implements Runnable {
161
162 private final CronExpression cronExpression;
163 private final Runnable runnable;
164 private CronScheduledFuture<?> scheduledFuture;
165
166 public CronRunnable(final Runnable runnable, final CronExpression cronExpression) {
167 this.cronExpression = cronExpression;
168 this.runnable = runnable;
169 }
170
171 public void setScheduledFuture(final CronScheduledFuture<?> future) {
172 this.scheduledFuture = future;
173 }
174
175 @Override
176 public void run() {
177 try {
178 runnable.run();
179 } catch(final Throwable ex) {
180 LOGGER.error("{} caught error running command", SIMPLE_NAME, ex);
181 } finally {
182 final Date fireDate = cronExpression.getNextValidTimeAfter(new Date());
183 final ScheduledFuture<?> future = schedule(this, nextFireInterval(fireDate), TimeUnit.MILLISECONDS);
184 scheduledFuture.reset(future, fireDate);
185 }
186 }
187 }
188
189 }