blob: 4daa5622367ad84f1678eaced1ecb88413a3e9bf [file] [log] [blame]
package org.eclipse.osbp.xtext.signal.common;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
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.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.osbp.xtext.signal.SignalActionEnum;
import org.eclipse.osbp.xtext.signal.SignalTypeEnum;
public class OSBPSignalWatcher {
/** the watcher service */
private WatchService watcher;
/** list of all created keys and paths */
private Map<WatchKey, Path> keys = null;
/** determines if the all tree of a directory has to be watched for changes*/
private boolean recursive = false;
// private static final long TIMEOUT = 10L;
// private static final TimeUnit TIMEUNIT = TimeUnit.SECONDS;
// for data-import
public static final String IMPORT_SUFFIX = "_imp";
// normal print to local
public static final String PRINT_SUFFIX = "_prt";
// pdf print in target directory
public static final String PDF_SUFFIX = "_pdf";
// send mail
public static final String MAIL_SUFFIX = "_sd";
// create notification
public static final String MESSAGE_SUFFIX = "_shw";
public OSBPSignalWatcher() throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey, Path>();
}
/**
* Process all events for keys queued to the watcher
*/
public void processEvents() {
for (;;) {
// wait for key to be signaled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
Path dir = keys.get(key);
if (dir == null) {
System.err.println("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
Kind<?> kind = event.kind();
// handle the OVERFLOW event
if (kind == OVERFLOW) {
continue;
}
// Context for directory entry event is the file name of entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
System.out.format("%s: %s\n", event.kind().name(), child);
// depending on what the user decide to do before ending
// before reseting the event
handleEvent(ev);
// if directory is created, and watching recursively, then
// register it and its sub-directories
if (recursive && (kind == ENTRY_CREATE)) {
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
// TODO OSBP: this needs to be adjust here
// for now a single key for all kind of changes will
// be created
registerAll(child, null);
}
} catch (IOException x) {
// ignore to keep sample readbale
}
}
}
// reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
}
}
/**
* Handling method for the user to extend
*
* @param event
* the {@link WatchEvent}
*/
public void handleEvent(WatchEvent<Path> event) {
// put your logic here
}
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>) event;
}
/**
* Register the given directory, and all its sub-directories, with the
* WatchService.
*
* @param rootpath
* {@link Path} the root path.
* @param signals
* @throws IOException
*/
public void registerAll(Path rootpath, String signals) throws IOException {
// register directory and sub-directories
Files.walkFileTree(rootpath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerPathToWatcher(dir, signals);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Register the given directory with the WatchService
*
* @param directory
* @param signals
* @param combined
* true to create only one {@link WatchKey} for all event types,
* false to create separate key for each event type.
* @throws IOException
*/
public void registerPathToWatcher(Path directory, String signals) throws IOException {
//TODO enter the register logic here
// registerPathToWatcher(directory, signals);
// watcher = FileSystems.getDefault().newWatchService();
// this.keys = new HashMap<WatchKey, Path>();
// if (signals != null && !signals.isEmpty()) {
// boolean iscreate =
// signals.contains(StandardWatchEventKinds.ENTRY_CREATE.toString());
// boolean isdelete =
// signals.contains(StandardWatchEventKinds.ENTRY_DELETE.toString());
// boolean ismodify =
// signals.contains(StandardWatchEventKinds.ENTRY_MODIFY.toString());
// // create one key for all kind of changes
// // and save the key for later use
// // TODO only applicable with xtext generation
// // keys.put(directory.register(watcher, iscreate ?
// StandardWatchEventKinds.ENTRY_CREATE :
// // null,
// // isdelete ? StandardWatchEventKinds.ENTRY_DELETE : null, ismodify ?
// StandardWatchEventKinds.ENTRY_MODIFY : null),
// // directory);
// keys.put(directory.register(watcher,
// StandardWatchEventKinds.ENTRY_CREATE,
// StandardWatchEventKinds.ENTRY_DELETE,
// StandardWatchEventKinds.ENTRY_MODIFY), directory);
// } else {
// // if none signals have been given by the user,
// // create a default key for all kind of changes
// // and save the key for later use
// keys.put(directory.register(watcher,
// StandardWatchEventKinds.ENTRY_CREATE,
// StandardWatchEventKinds.ENTRY_DELETE,
// StandardWatchEventKinds.ENTRY_MODIFY), directory);
// }
}
/**
* Checks if the given {@link WatchKey} is valid.
*
* @return true if yes, false if not
*/
public boolean isKeyValid(WatchKey key) {
return key != null ? key.isValid() : false;
}
/**
*
* @return
*/
public int getWatcherState() {
return watcher != null ? 1 : -1;
}
/**
* Closes the watcher service
*
* @return true if yes or non existing, false if not
*/
public boolean closeWatcher() {
try {
if (watcher != null) {
watcher.close();
}
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* Get the list of registered directories.
*
* @return {@link Collection<Path>} {@link #directories}
*/
public Collection<Path> getRegisteredDirectories() {
return keys.values();
}
/**
* Gets the list of registered keys.
*
* @return {@link Set<WatchKey>}
*/
public Set<WatchKey> getRegisteredKeys() {
return keys.keySet();
}
/**
* Gets the list of registered keys and their paths.
*
* @return {@link Map<WatchKey,Path>}
*/
public Map<WatchKey, Path> getRegisteredKeysAndPaths() {
return keys;
}
/**
* Gets the watcher.
*
* @return {@link WatchService}
*/
public WatchService getWatcher() {
return watcher;
}
/**
* Register the path and trigger the processing event operation to poll key
* event.
*
* @throws IOException
*/
public void startWatcher(String path, SignalTypeEnum signal) throws IOException {
registerPathToWatcher(Paths.get(path), getAppropriateKey(signal));
processEvents();
}
/**
* Convenience operation gives the apporpriate key set for
*
* @param type
* @return
*/
public String getAppropriateKey(SignalTypeEnum type) {
switch (type) {
case CREATESIGNALS:
return StandardWatchEventKinds.ENTRY_CREATE.toString();
case DELETESIGNALS:
return StandardWatchEventKinds.ENTRY_DELETE.toString();
case MODIFYSIGNALS:
return StandardWatchEventKinds.ENTRY_MODIFY.toString();
case ALL:
return StandardWatchEventKinds.ENTRY_CREATE.toString() + StandardWatchEventKinds.ENTRY_DELETE.toString()
+ StandardWatchEventKinds.ENTRY_MODIFY.toString();
default:
return StandardWatchEventKinds.OVERFLOW.toString();
}
}
/**
* Provides an action based on the filename.
*
* @param filename
* filename
* @return
*/
public SignalActionEnum checkFileMask(String filename) {
if (filename != null && !filename.isEmpty()) {
if (filename.toLowerCase().contains(IMPORT_SUFFIX)) {
// persist data into a db
return SignalActionEnum.DATAIMPORT;
} else if (filename.toLowerCase().contains(PRINT_SUFFIX)) {
// print a report from a printer
return SignalActionEnum.PRINT;
} else if (filename.toLowerCase().contains(PDF_SUFFIX)) {
// create a pdf or report of a bpm task
return SignalActionEnum.PDFPRINT;
} else if (filename.toLowerCase().contains(MAIL_SUFFIX)) {
// send a mail
return SignalActionEnum.MAIL;
} else if (filename.toLowerCase().contains(MESSAGE_SUFFIX)) {
// show notification
return SignalActionEnum.MESSAGEPROMPT;
}
}
return SignalActionEnum.NONE; // do nothing
}
}