001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.config;
018    
019    import java.io.File;
020    import java.util.List;
021    
022    /**
023     * Configuration monitor that periodically checks the timestamp of the configuration file and calls the
024     * ConfigurationListeners when an update occurs.
025     */
026    public class FileConfigurationMonitor implements ConfigurationMonitor {
027    
028        private static final int MASK = 0x0f;
029    
030        private static final int MIN_INTERVAL = 5;
031    
032        private static final int MILLIS_PER_SECOND = 1000;
033    
034        private final File file;
035    
036        private long lastModified;
037    
038        private final List<ConfigurationListener> listeners;
039    
040        private final int interval;
041    
042        private long nextCheck;
043    
044        private volatile int counter = 0;
045    
046        private final Reconfigurable reconfigurable;
047    
048        /**
049         * Constructor.
050         * @param reconfigurable The Configuration that can be reconfigured.
051         * @param file The File to monitor.
052         * @param listeners The List of ConfigurationListeners to notify upon a change.
053         * @param interval The monitor interval in seconds. The minimum interval is 5 seconds.
054         */
055        public FileConfigurationMonitor(final Reconfigurable reconfigurable, final File file,
056                                        final List<ConfigurationListener> listeners,
057                                        final int interval) {
058            this.reconfigurable = reconfigurable;
059            this.file = file;
060            this.lastModified = file.lastModified();
061            this.listeners = listeners;
062            this.interval = (interval < MIN_INTERVAL ? MIN_INTERVAL : interval) * MILLIS_PER_SECOND;
063            this.nextCheck = System.currentTimeMillis() + interval;
064        }
065    
066        /**
067         * Called to determine if the configuration has changed.
068         */
069        public void checkConfiguration() {
070            if ((++counter & MASK) == 0) {
071                synchronized (this) {
072                    final long current = System.currentTimeMillis();
073                    if (current >= nextCheck) {
074                        nextCheck = current + interval;
075                        if (file.lastModified() > lastModified) {
076                            lastModified = file.lastModified();
077                            for (final ConfigurationListener listener : listeners) {
078                                listener.onChange(reconfigurable);
079                            }
080                        }
081                    }
082                }
083            }
084        }
085    }