/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
/**
* Copyright (c) 2014-2016 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.core.service;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base class for OSGI services that access to file system by Java WatchService. <br />
* See the WatchService <a href=
* "http://docs.oracle.com/javase/7/docs/api/java/nio/file/WatchService.html"
* >java docs</a> for more details
*
* @author Fabio Marini
* @author Dimitar Ivanov - added javadoc; introduced WatchKey to directory mapping for the queue reader
* @author Ana Dimova - reduce to a single watch thread for all class instances of {@link AbstractWatchService}
*
*/
public abstract class AbstractWatchService {
/**
* Default logger for ESH Watch Services
*/
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected String pathToWatch;
protected AbstractWatchService(String pathToWatch) {
this.pathToWatch = pathToWatch;
}
/**
* The queue reader
*/
protected WatchQueueReader watchQueueReader;
/**
* Method to call on service activation
*/
public void activate() {
Path pathToWatch = getSourcePath();
if (pathToWatch != null) {
watchQueueReader = WatchQueueReader.getInstance();
watchQueueReader.customizeWatchQueueReader(this, pathToWatch, watchSubDirectories());
}
}
/**
* Method to call on service deactivation
*/
public void deactivate() {
WatchQueueReader watchQueueReader = this.watchQueueReader;
if (watchQueueReader != null) {
watchQueueReader.stopWatchService(this);
}
this.watchQueueReader = null;
}
/**
* @return the path to be watched as a {@link String}. The returned path should be applicable for creating a
* {@link Path} with the {@link Paths#get(String, String...)} method.
*/
public Path getSourcePath() {
if (StringUtils.isNotBlank(pathToWatch)) {
return Paths.get(pathToWatch);
}
return null;
}
/**
* Determines whether the subdirectories of the source path (determined by the {@link #getSourcePath()}) will be
* watched or not.
*
* @return <code>true</code> if the subdirectories will be watched and <code>false</code> if only the source path
* (determined by the {@link #getSourcePath()}) will be watched
*/
protected abstract boolean watchSubDirectories();
/**
* Provides the {@link WatchKey}s for the registration of the directory, which will be registered in the watch
* service.
*
* @param directory the directory, which will be registered in the watch service
* @return The array of {@link WatchKey}s for the registration or <code>null</code> if no registration has been
* done.
*/
protected abstract Kind<?>[] getWatchEventKinds(Path directory);
/**
* If the queue reader is watching the directory changes, all the watch events will be processed. Otherwise the
* events for changed directories will be skipped. For example, on some platforms an event for modified directory is
* generated when a new file is created within the directory. However, this behavior could vary a lot, depending on
* the platform (for more information see "Platform dependencies" section in the {@link WatchService} documentation)
*
* @param directory
*
* @param watchDirectoryChanges set to <code>true</code> if the directory events have to be processed and
* <code>false</code> otherwise
*/
protected boolean getWatchingDirectoryChanges(Path directory) {
return true;
}
/**
* Processes the given watch event. Note that the kind and the number of the events for the watched directory is a
* platform dependent (see the "Platform dependencies" sections of {@link WatchService}).
*
* @param event the watch event to be handled
* @param kind the event's kind
* @param path the path of the event (resolved to the {@link #baseWatchedDir})
*/
protected abstract void processWatchEvent(WatchEvent<?> event, Kind<?> kind, Path path);
}