com.pastdev.jsch.nio.file.UnixSshFileSystemWatchService Maven / Gradle / Ivy
package com.pastdev.jsch.nio.file;
import java.io.IOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchEvent.Modifier;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UnixSshFileSystemWatchService implements WatchService {
private static Logger logger = LoggerFactory.getLogger( UnixSshFileSystemWatchService.class );
private static final long DEFAULT_POLLING_INTERVAL = 10;
private static final TimeUnit DEFAULT_POLLING_INTERVAL_TIME_UNIT = TimeUnit.MINUTES;
private long pollingInterval;
private TimeUnit pollingIntervalTimeUnit;
private volatile boolean closed;
private final ExecutorService executorService;
private final LinkedBlockingDeque pendingKeys;
private boolean useINotifyWatchKey = false;
private final Map> watchKeyFutures;
private final Map watchKeys;
private final Lock watchKeysLock;
private UnixSshFileSystemWatchService() {
logger.debug( "creating new watch service polling every {} {}", pollingInterval, pollingIntervalTimeUnit );
this.pendingKeys = new LinkedBlockingDeque<>();
this.executorService = Executors.newCachedThreadPool();
this.watchKeys = new HashMap<>();
this.watchKeyFutures = new HashMap<>();
this.watchKeysLock = new ReentrantLock();
}
@Override
public void close() throws IOException {
if ( closed ) return;
closed = true;
}
boolean closed() {
return closed;
}
void enqueue( WatchKey watchKey ) {
ensureOpen();
pendingKeys.add( watchKey );
}
void ensureOpen() {
if ( closed ) throw new ClosedWatchServiceException();
}
public static WatchService inotifyWatchService() {
UnixSshFileSystemWatchService service = new UnixSshFileSystemWatchService();
service.useINotifyWatchKey = true;
return service;
}
private UnixSshPathWatchKey newWatchKey( UnixSshPath path, Kind>[] events ) {
return useINotifyWatchKey
? new UnixSshPathINotifyWatchKey( this, path, events )
: new UnixSshPathWatchKey( this, path, events, pollingInterval, pollingIntervalTimeUnit );
}
@Override
public WatchKey poll() {
ensureOpen();
return pendingKeys.poll();
}
@Override
public WatchKey poll( long timeout, TimeUnit unit ) throws InterruptedException {
ensureOpen();
return pendingKeys.poll( timeout, unit );
}
public static UnixSshFileSystemWatchService pollingWatchService( Long pollingInterval, TimeUnit pollingIntervalTimeUnit ) {
UnixSshFileSystemWatchService service = new UnixSshFileSystemWatchService();
service.pollingInterval = pollingInterval == null ? DEFAULT_POLLING_INTERVAL : pollingInterval;
service.pollingIntervalTimeUnit = pollingIntervalTimeUnit == null
? DEFAULT_POLLING_INTERVAL_TIME_UNIT : pollingIntervalTimeUnit;
return service;
}
UnixSshPathWatchKey register( UnixSshPath path, Kind>[] events, Modifier... modifiers ) {
try {
watchKeysLock.lock();
if ( watchKeys.containsKey( path ) ) {
return watchKeys.get( path );
}
UnixSshPathWatchKey watchKey = newWatchKey( path, events );
watchKeys.put( path, watchKey );
watchKeyFutures.put( path, executorService.submit( watchKey ) );
return watchKey;
}
finally {
watchKeysLock.unlock();
}
}
void unregister( UnixSshPathWatchKey watchKey ) {
try {
watchKeysLock.lock();
UnixSshPath path = watchKey.watchable();
if ( !watchKeys.containsKey( path ) ) {
return;
}
watchKeyFutures.remove( path ).cancel( true );
watchKeys.remove( path );
}
finally {
watchKeysLock.unlock();
}
}
@Override
public WatchKey take() throws InterruptedException {
ensureOpen();
return pendingKeys.take();
}
}