Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2012-2018 the original author or authors.
*
* 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 ninja.build;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.nio.file.SensitivityWatchEventModifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class WatchAndRestartMachine implements Runnable {
private static final Logger log = LoggerFactory.getLogger(WatchAndRestartMachine.class);
private boolean shutdown;
private final DelayedRestartTrigger restartTrigger;
private final Set includes;
private final Set excludes;
private final WatchService watchService;
private final Map mapOfWatchKeysToPaths;
private final AtomicInteger takeCount;
public WatchAndRestartMachine(
Path directoryToRecursivelyWatch,
Set includes,
Set excludes,
DelayedRestartTrigger restartTrigger) throws IOException {
this(new HashSet<>(Arrays.asList(directoryToRecursivelyWatch)),
includes, excludes, restartTrigger);
}
public WatchAndRestartMachine(
Set directoriesToRecursivelyWatch,
Set includes,
Set excludes,
DelayedRestartTrigger restartTrigger) throws IOException {
this.watchService = FileSystems.getDefault().newWatchService();
this.mapOfWatchKeysToPaths = new HashMap<>();
this.includes = includes;
this.excludes = excludes;
this.restartTrigger = restartTrigger;
this.takeCount = new AtomicInteger(0);
for (Path path: directoriesToRecursivelyWatch) {
registerAll(path);
}
}
public void shutdown() {
this.shutdown = true;
// doesn't do anything but does prevent logging an error
}
private void registerAll(final Path path) throws IOException {
// register directory and sub-directories
Files.walkFileTree(path, new SimpleFileVisitor() {
@Override
public FileVisitResult preVisitDirectory(Path path,
BasicFileAttributes attrs)
throws IOException {
register(path);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Register the given path with the WatchService
*/
private void register(Path path) throws IOException {
////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//// USUALLY THIS IS THE DEFAULT WAY TO REGISTER THE EVENTS:
////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// WatchKey watchKey = path.register(
// watchService,
// ENTRY_CREATE,
// ENTRY_DELETE,
// ENTRY_MODIFY);
////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//// BUT THIS IS DAMN SLOW (at least on a Mac)
//// THEREFORE WE USE EVENTS FROM COM.SUN PACKAGES THAT ARE WAY FASTER
//// THIS MIGHT BREAK COMPATIBILITY WITH OTHER JDKs
//// MORE: http://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-else
////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
WatchKey watchKey = path.register(
watchService,
new WatchEvent.Kind[]{
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE
},
SensitivityWatchEventModifier.HIGH);
mapOfWatchKeysToPaths.put(watchKey, path);
}
@Override
public void run() {
for (;;) {
WatchKey watchKey;
try {
watchKey = watchService.take();
takeCount.incrementAndGet();
} catch (InterruptedException e) {
if (!shutdown) {
log.error("Unexpectedly interrupted while waiting for take()", e);
}
return;
}
Path path = mapOfWatchKeysToPaths.get(watchKey);
if (path == null) {
log.error("WatchKey not recognized!!");
continue;
}
for (WatchEvent> watchEvent : watchKey.pollEvents()) {
WatchEvent.Kind watchEventKind = watchEvent.kind();
// TBD - provide example of how OVERFLOW watchEvent is handled
if (watchEventKind == OVERFLOW) {
continue;
}
// Context for directory entry watchEvent is the file name of entry
WatchEvent ev = (WatchEvent) watchEvent;
Path name = ev.context();
Path child = path.resolve(name);
if (watchEventKind == ENTRY_MODIFY) {
// we are not interested in events from parent directories...
if (!child.toFile().isDirectory()) {
handleNewOrModifiedFile("Modified", child);
}
}
// if directory is created, then register it and its sub-directories recursively
if (watchEventKind == ENTRY_CREATE) {
if (!child.toFile().isDirectory()) {
handleNewOrModifiedFile("New", child);
}
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
registerAll(child);
}
} catch (IOException e) {
log.error("Something fishy happened. Unable to register new dir for watching", e);
}
}
}
// reset watchKey and remove from set if directory no longer accessible
boolean valid = watchKey.reset();
if (!valid) {
mapOfWatchKeysToPaths.remove(watchKey);
// all directories are inaccessible
if (mapOfWatchKeysToPaths.isEmpty()) {
break;
}
}
}
}
public void handleNewOrModifiedFile(String newOrMod, Path path) {
String f = path.toFile().getAbsolutePath();
log.debug("{} file detected: {}", newOrMod, f);
RuleMatch match = matchRule(includes, excludes, f);
log.debug(" matched rule: type={}, pattern={}, proceed={}", match.type, match.pattern, match.proceed);
if (match.proceed) {
log.debug(" will trigger restart", newOrMod, f);
restartTrigger.trigger();
}
else {
log.debug(" will not trigger restart");
}
}
public static enum RuleType {
none,
include,
exclude
}
public static class RuleMatch {
final RuleType type;
final String pattern;
final boolean proceed;
public RuleMatch(RuleType type, String pattern, boolean proceed) {
this.type = type;
this.pattern = pattern;
this.proceed = proceed;
}
}
public static RuleMatch matchRule(Set includes, Set excludes, String string) {
if (includes != null) {
for (String regex: includes) {
if (string.matches(regex)) {
return new RuleMatch(RuleType.include, regex, true);
}
}
}
if (excludes != null) {
for (String regex: excludes) {
if (string.matches(regex)) {
return new RuleMatch(RuleType.exclude, regex, false);
}
}
}
return new RuleMatch(RuleType.none, "", true);
}
public static boolean checkIfWouldBeExcluded(Set patterns, String string) {
// use "excludes" above to use this for testing
return !matchRule(null, patterns, string).proceed;
}
}