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.io.File; 020import java.util.HashMap; 021import java.util.Map; 022import java.util.concurrent.ConcurrentHashMap; 023import java.util.concurrent.ConcurrentMap; 024import java.util.concurrent.ScheduledFuture; 025import java.util.concurrent.TimeUnit; 026 027import org.apache.logging.log4j.Logger; 028import org.apache.logging.log4j.core.AbstractLifeCycle; 029import org.apache.logging.log4j.core.config.ConfigurationScheduler; 030import org.apache.logging.log4j.status.StatusLogger; 031 032/** 033 * Manages FileWatchers. 034 */ 035public class WatchManager extends AbstractLifeCycle { 036 037 private static Logger logger = StatusLogger.getLogger(); 038 private final ConcurrentMap<File, FileMonitor> watchers = new ConcurrentHashMap<>(); 039 private int intervalSeconds = 0; 040 private ScheduledFuture<?> future; 041 private final ConfigurationScheduler scheduler; 042 043 public WatchManager(ConfigurationScheduler scheduler) { 044 this.scheduler = scheduler; 045 } 046 047 public void setIntervalSeconds(int intervalSeconds) { 048 if (!isStarted()) { 049 if (this.intervalSeconds > 0 && intervalSeconds == 0) { 050 scheduler.decrementScheduledItems(); 051 } else if (this.intervalSeconds == 0 && intervalSeconds > 0) { 052 scheduler.incrementScheduledItems(); 053 } 054 this.intervalSeconds = intervalSeconds; 055 } 056 } 057 058 public int getIntervalSeconds() { 059 return this.intervalSeconds; 060 } 061 062 @Override 063 public void start() { 064 super.start(); 065 if (intervalSeconds > 0) { 066 future = scheduler.scheduleWithFixedDelay(new WatchWorker(), intervalSeconds, intervalSeconds, 067 TimeUnit.SECONDS); 068 } 069 } 070 071 @Override 072 public void stop() { 073 future.cancel(true); 074 super.stop(); 075 } 076 077 public void watchFile(File file, FileWatcher watcher) { 078 watchers.put(file, new FileMonitor(file.lastModified(), watcher)); 079 080 } 081 082 public Map<File, FileWatcher> getWatchers() { 083 Map<File, FileWatcher> map = new HashMap<>(); 084 for (Map.Entry<File, FileMonitor> entry : watchers.entrySet()) { 085 map.put(entry.getKey(), entry.getValue().fileWatcher); 086 } 087 return map; 088 } 089 090 private class WatchWorker implements Runnable { 091 092 @Override 093 public void run() { 094 for (Map.Entry<File, FileMonitor> entry : watchers.entrySet()) { 095 File file = entry.getKey(); 096 FileMonitor fileMonitor = entry.getValue(); 097 long lastModfied = file.lastModified(); 098 if (fileModified(fileMonitor, lastModfied)) { 099 logger.info("File {} was modified", file.toString()); 100 fileMonitor.lastModified = lastModfied; 101 fileMonitor.fileWatcher.fileModified(file); 102 } 103 } 104 } 105 106 private boolean fileModified(FileMonitor fileMonitor, long lastModfied) { 107 return lastModfied != fileMonitor.lastModified; 108 } 109 } 110 111 private class FileMonitor { 112 private final FileWatcher fileWatcher; 113 private long lastModified; 114 115 public FileMonitor(long lastModified, FileWatcher fileWatcher) { 116 this.fileWatcher = fileWatcher; 117 this.lastModified = lastModified; 118 } 119 } 120}