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.io.File;
20 import java.util.List;
21 import java.util.concurrent.atomic.AtomicInteger;
22 import java.util.concurrent.locks.Lock;
23 import java.util.concurrent.locks.ReentrantLock;
24
25
26
27
28
29 public class FileConfigurationMonitor implements ConfigurationMonitor {
30
31 private static final int MASK = 0x0f;
32
33 private static final int MIN_INTERVAL = 5;
34
35 private static final int MILLIS_PER_SECOND = 1000;
36
37 private final File file;
38
39 private long lastModified;
40
41 private final List<ConfigurationListener> listeners;
42
43 private final int intervalSeconds;
44
45 private long nextCheck;
46
47 private final AtomicInteger counter = new AtomicInteger(0);
48
49 private static final Lock LOCK = new ReentrantLock();
50
51 private final Reconfigurable reconfigurable;
52
53
54
55
56
57
58
59
60 public FileConfigurationMonitor(final Reconfigurable reconfigurable, final File file,
61 final List<ConfigurationListener> listeners,
62 final int intervalSeconds) {
63 this.reconfigurable = reconfigurable;
64 this.file = file;
65 this.lastModified = file.lastModified();
66 this.listeners = listeners;
67 this.intervalSeconds = (intervalSeconds < MIN_INTERVAL ? MIN_INTERVAL : intervalSeconds) * MILLIS_PER_SECOND;
68 this.nextCheck = System.currentTimeMillis() + intervalSeconds;
69 }
70
71
72
73
74 @Override
75 public void checkConfiguration() {
76 final long current = System.currentTimeMillis();
77 if (((counter.incrementAndGet() & MASK) == 0) && (current >= nextCheck)) {
78 LOCK.lock();
79 try {
80 nextCheck = current + intervalSeconds;
81 if (file.lastModified() > lastModified) {
82 lastModified = file.lastModified();
83 for (final ConfigurationListener listener : listeners) {
84 final Thread thread = new Thread(new ReconfigurationWorker(listener, reconfigurable));
85 thread.setDaemon(true);
86 thread.start();
87 }
88 }
89 } finally {
90 LOCK.unlock();
91 }
92 }
93 }
94
95 private class ReconfigurationWorker implements Runnable {
96
97 private final ConfigurationListener listener;
98 private final Reconfigurable reconfigurable;
99
100 public ReconfigurationWorker(final ConfigurationListener listener, final Reconfigurable reconfigurable) {
101 this.listener = listener;
102 this.reconfigurable = reconfigurable;
103 }
104
105 @Override
106 public void run() {
107 listener.onChange(reconfigurable);
108 }
109 }
110 }