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 */
017package org.apache.logging.log4j.core.util;
018
019import java.util.List;
020
021import org.apache.logging.log4j.core.config.Configuration;
022import org.apache.logging.log4j.core.config.ConfigurationListener;
023import org.apache.logging.log4j.core.config.Reconfigurable;
024
025/**
026 * Watcher for configuration files. Causes a reconfiguration when a file changes.
027 */
028public abstract class AbstractWatcher implements Watcher {
029
030    private final Reconfigurable reconfigurable;
031    private final List<ConfigurationListener> configurationListeners;
032    private final Log4jThreadFactory threadFactory;
033    private final Configuration configuration;
034    private Source source;
035
036    public AbstractWatcher(final Configuration configuration, final Reconfigurable reconfigurable,
037            final List<ConfigurationListener> configurationListeners) {
038        this.configuration = configuration;
039        this.reconfigurable = reconfigurable;
040        this.configurationListeners = configurationListeners;
041        this.threadFactory = configurationListeners != null ?
042            Log4jThreadFactory.createDaemonThreadFactory("ConfiguratonFileWatcher") : null;
043    }
044
045    @Override
046    public List<ConfigurationListener> getListeners() {
047        return configurationListeners;
048    }
049
050    @Override
051    public void modified() {
052        for (final ConfigurationListener configurationListener : configurationListeners) {
053            final Thread thread = threadFactory.newThread(new ReconfigurationRunnable(configurationListener, reconfigurable));
054            thread.start();
055        }
056    }
057
058    public Configuration getConfiguration() {
059        return configuration;
060    }
061
062    @Override
063    public abstract long getLastModified();
064
065    @Override
066    public abstract boolean isModified();
067
068    @Override
069    public void watching(Source source) {
070        this.source = source;
071    }
072
073    @Override
074    public Source getSource() {
075        return source;
076    }
077
078    /**
079     * Helper class for triggering a reconfiguration in a background thread.
080     */
081    public static class ReconfigurationRunnable implements Runnable {
082
083        private final ConfigurationListener configurationListener;
084        private final Reconfigurable reconfigurable;
085
086        public ReconfigurationRunnable(final ConfigurationListener configurationListener, final Reconfigurable reconfigurable) {
087            this.configurationListener = configurationListener;
088            this.reconfigurable = reconfigurable;
089        }
090
091        @Override
092        public void run() {
093            configurationListener.onChange(reconfigurable);
094        }
095    }
096}