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(final ConfigurationScheduler scheduler) { 044 this.scheduler = scheduler; 045 } 046 047 public void setIntervalSeconds(final 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 WatchRunnable(), intervalSeconds, intervalSeconds, 067 TimeUnit.SECONDS); 068 } 069 } 070 071 @Override 072 public boolean stop(final long timeout, final TimeUnit timeUnit) { 073 setStopping(); 074 final boolean stopped = stop(future); 075 setStopped(); 076 return stopped; 077 } 078 079 public void watchFile(final File file, final FileWatcher watcher) { 080 watchers.put(file, new FileMonitor(file.lastModified(), watcher)); 081 082 } 083 084 public Map<File, FileWatcher> getWatchers() { 085 final Map<File, FileWatcher> map = new HashMap<>(); 086 for (final Map.Entry<File, FileMonitor> entry : watchers.entrySet()) { 087 map.put(entry.getKey(), entry.getValue().fileWatcher); 088 } 089 return map; 090 } 091 092 private class WatchRunnable implements Runnable { 093 094 @Override 095 public void run() { 096 for (final Map.Entry<File, FileMonitor> entry : watchers.entrySet()) { 097 final File file = entry.getKey(); 098 final FileMonitor fileMonitor = entry.getValue(); 099 final long lastModfied = file.lastModified(); 100 if (fileModified(fileMonitor, lastModfied)) { 101 logger.info("File {} was modified on {}, previous modification was {}", file, lastModfied, fileMonitor.lastModifiedMillis); 102 fileMonitor.lastModifiedMillis = lastModfied; 103 fileMonitor.fileWatcher.fileModified(file); 104 } 105 } 106 } 107 108 private boolean fileModified(final FileMonitor fileMonitor, final long lastModifiedMillis) { 109 return lastModifiedMillis != fileMonitor.lastModifiedMillis; 110 } 111 } 112 113 private class FileMonitor { 114 private final FileWatcher fileWatcher; 115 private long lastModifiedMillis; 116 117 public FileMonitor(final long lastModifiedMillis, final FileWatcher fileWatcher) { 118 this.fileWatcher = fileWatcher; 119 this.lastModifiedMillis = lastModifiedMillis; 120 } 121 122 @Override 123 public String toString() { 124 return "FileMonitor [fileWatcher=" + fileWatcher + ", lastModifiedMillis=" + lastModifiedMillis + "]"; 125 } 126 } 127 128 @Override 129 public String toString() { 130 return "WatchManager [intervalSeconds=" + intervalSeconds + ", watchers=" + watchers + ", scheduler=" 131 + scheduler + ", future=" + future + "]"; 132 } 133}