com.ovea.tadjin.util.fs.FrequencyFileSystemWatcher Maven / Gradle / Ivy
The newest version!
/**
* Copyright (C) 2011 Ovea
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ovea.tadjin.util.fs;
import java.io.File;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Mathieu Carbou ([email protected])
*/
public final class FrequencyFileSystemWatcher implements FileSystemWatcher {
private static final Logger LOGGER = Logger.getLogger(FrequencyFileSystemWatcher.class.getName());
private final List listeners = new CopyOnWriteArrayList();
private volatile ScheduledExecutorService executor;
@Override
public void addListener(FileListener listener) {
listeners.add(listener);
}
@Override
public void start() {
if (executor == null) {
executor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, new ThreadPoolExecutor.CallerRunsPolicy());
}
}
@Override
public void stop() {
if (executor != null) {
ScheduledExecutorService e = executor;
executor = null;
e.shutdown();
}
}
@Override
public void watchDirectory(final long sleepDelay, final TimeUnit unit, final File directory, String... includes) {
if (executor != null) {
final AntFileScanner scanner = AntFileScanner.create(true, includes, new String[0]);
executor.scheduleWithFixedDelay(new Runnable() {
Map states = null;
@Override
public void run() {
try {
Map oldStates = getStates();
states = scan();
for (Map.Entry entry : getStates().entrySet()) {
FileState old = oldStates.remove(entry.getKey());
if (old == null) {
for (FileListener listener : listeners) {
listener.onAddition(entry.getKey());
}
} else if (old.time != entry.getValue().time) {
for (FileListener listener : listeners) {
listener.onChange(entry.getKey());
}
}
}
for (File file : oldStates.keySet()) {
for (FileListener listener : listeners) {
listener.onRemoval(file);
}
}
} catch (Exception e) {
if (!Thread.currentThread().isInterrupted()) {
LOGGER.log(Level.SEVERE, "FileSystem watching job error: " + e.getMessage(), e);
}
}
}
Map getStates() {
if (states == null) {
states = scan();
for (File file : states.keySet()) {
for (FileListener listener : listeners) {
listener.onAddition(file);
}
}
}
return states;
}
Map scan() {
Map states = new LinkedHashMap();
if (directory.exists() && directory.canRead())
for (File f : scanner.scan(directory))
states.put(f, new FileState(f));
return states;
}
}, 0, sleepDelay, unit);
}
}
private final ConcurrentHashMap> files = new ConcurrentHashMap>();
@Override
public void watchFile(long sleepDelay, TimeUnit unit, final File file) {
if (files.containsKey(file)) return;
files.put(file, Void.TYPE);
executor.scheduleWithFixedDelay(new Runnable() {
FileState state = new FileState(file);
@Override
public void run() {
FileState old = state;
state = new FileState(file);
if (old.exist && !state.exist) {
for (FileListener listener : listeners) {
listener.onRemoval(file);
}
} else if (!old.exist && state.exist) {
for (FileListener listener : listeners) {
listener.onAddition(file);
}
} else if (old.exist && state.exist && old.time != state.time) {
for (FileListener listener : listeners) {
listener.onChange(file);
}
}
}
}, 0, sleepDelay, unit);
}
private static final class FileState {
final boolean exist;
final long time;
FileState(File file) {
this.exist = file.exists();
this.time = file.lastModified();
}
}
}