/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.vfs.watcher;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.function.Consumer;
import static org.eclipse.che.api.vfs.watcher.FileWatcherUtils.toNormalPath;
/**
* Facade for all dynamic file watcher system related operations.
*/
@Singleton
public class FileWatcherManager {
public final static Consumer<String> EMPTY_CONSUMER = it -> {
};
private static final Logger LOG = LoggerFactory.getLogger(FileWatcherManager.class);
private final FileWatcherByPathValue fileWatcherByPathValue;
private final FileWatcherByPathMatcher fileWatcherByPathMatcher;
private final FileWatcherService service;
private final Path root;
@Inject
public FileWatcherManager(@Named("che.user.workspaces.storage") File root, FileWatcherByPathValue watcherByPathValue,
FileWatcherByPathMatcher watcherByPathMatcher, FileWatcherService service) {
this.fileWatcherByPathMatcher = watcherByPathMatcher;
this.fileWatcherByPathValue = watcherByPathValue;
this.service = service;
this.root = root.toPath().normalize().toAbsolutePath();
}
/**
* Suspend dynamic file watching system. If already suspended does nothing
*/
public void suspend() {
service.suspend();
}
/**
* Resume dynamic file watching system. If already resumed does nothing
*/
public void resume() {
service.resume();
}
/**
* Start watching a file system item by specifying its path. If path points
* to a file than only file related events are taken into account, if path
* points to a folder than all folder entries related events are taken into
* account. Path is expected to be in absolute form in internal virtual
* file system format.
*
* To react on events related to an aforementioned item you can
* specify {@link Consumer} for create, modify and delete
* event correspondingly. It is possible to omit one ore more event
* consumers if it is needed by using {@link this#EMPTY_CONSUMER} stub.
*
* On successful start you receive a registration identifier to distinguish
* your specific consumer set as there can be registered arbitrary number of
* consumers to a single path.
*
* @param path
* absolute internal path
* @param create
* consumer for create event
* @param modify
* consumer for modify event
* @param delete
* consumer for delete event
*
* @return operation set identifier
*/
public int registerByPath(String path, Consumer<String> create, Consumer<String> modify, Consumer<String> delete) {
LOG.debug("Registering operations to an item with path '{}'", path);
return fileWatcherByPathValue.watch(toNormalPath(root, path), create, modify, delete);
}
/**
* Stops watching a file system item. More accurately it cancels
* registration of an operation set identified by a parameter to
* a specific path, so any event related to that path no longer calls
* corresponding consumers. However if there are other consumers
* registered to that specific path they are still active and can be
* called on event.
*
* @param id
* operation set identifier
*/
public void unRegisterByPath(int id) {
LOG.debug("Canceling registering of an operation with id '{}' registered to an item with path", id);
fileWatcherByPathValue.unwatch(id);
}
/**
* Start watching a file system item by specifying its path matcher. Any
* item on file system that matches is registered and being watched. If
* matched path points to a file than only file related events are taken
* into account, if matched path points to a folder than all folder entries
* related events are taken into account.
*
* To react on events related to an aforementioned item you can
* specify {@link Consumer} for create, modify and delete
* event correspondingly. It is possible to omit one ore more event
* consumers if it is needed by using {@link this#EMPTY_CONSUMER} stub.
*
* On successful start you receive a registration identifier to distinguish
* specific consumer sets as there can be registered arbitrary number of
* consumers to a single path matcher.
*
* @param matcher
* absolute internal path
* @param create
* consumer for create event
* @param modify
* consumer for modify event
* @param delete
* consumer for delete event
*
* @return operation set identifier
*/
public int registerByMatcher(PathMatcher matcher, Consumer<String> create, Consumer<String> modify, Consumer<String> delete) {
LOG.debug("Registering operations to an item with matcher '{}'", matcher);
return fileWatcherByPathMatcher.watch(matcher, create, modify, delete);
}
/**
* Stops watching all file system items registered to corresponding path
* matcher. More accurately it cancels registration of an operation set
* identified by a parameter to all items defined by path matcher, so any
* event related to any path that matches the matcher no longer calls
* corresponding consumers. However if there are other consumers
* registered to that specific path matcher they are still active and can
* be called on event.
*
* @param id
* operation set identifier
*/
public void unRegisterByMatcher(int id) {
LOG.debug("Canceling registering of an operation with id '{}' registered to path matcher", id);
fileWatcherByPathMatcher.unwatch(id);
}
}