I started a Quarkus project, which (in part) shall watch for file changes on a text-file, read the added line(s) and then sends the added line(s) through a websocket connection to a client.
For watching the file changes and reading those I created the following class:
public class McServerService {
private String directory;
private List<String> currentLog;
private Observable<List<String>> observableLog;
private Thread logObserverThread;
public McServerService (String directory) {
this.currentLog = new ArrayList<String>();
this.observableLog = Observable.fromCallable(() -> this.currentLog);
this.directory = directory;
}
public void startWatching () {
this.logObserverThread = new Thread(new LogObserverThreadImpl(this.directory));
this.logObserverThread.start();
}
public void subscribeToLog (Observer<? super List<String>> observer) {
this.observableLog.subscribe(observer);
}
private class LogObserverThreadImpl implements Runnable {
BufferedReader br;
WatchService watchService;
private LogObserverThreadImpl (String directory) {
try {
this.br = new BufferedReader(new java.io.FileReader(directory + "\\" + "latest.log"));
String nextLine;
while ((nextLine = this.br.readLine()) != null) {
McServerService.this.currentLog.add(nextLine);
System.out.println(nextLine);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void run() {
Path path = Paths.get(directory);
try {
System.out.println("entered try");
this.watchService = FileSystems.getDefault().newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey key;
while ((key = this.watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
if (event.context().toString().equals("latest.log")) {
String line = this.br.readLine();
McServerService.this.currentLog.add(line);
System.out.println(line);
}
}
key.reset();
}
System.out.println("after while");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Now the websocket would be handled by this class:
#ServerEndpoint("/test")
#ApplicationScoped
public class McServerWebSocket {
Map<String, Session> sessions = new ConcurrentHashMap<>();
McServerService mss = new McServerService("D:\\Spiele\\Minecraft");
#OnOpen
public void onOpen(Session session, #PathParam("name") String name) {
sessions.put(name, session);
}
#OnClose
public void onClose(Session session, #PathParam("name") String name) {
sessions.remove(name);
}
#OnError
public void onError(Session session, #PathParam("name") String name, Throwable throwable) {
sessions.remove(name);
}
#OnMessage
public void onMessage(String message, #PathParam("name") String name) {
Session c_session = sessions.get(name);
c_session.getAsyncRemote().sendObject("insert");
}
private class ConsoleLogObserverImpl implements Observer<List<String>>{
private ConsoleLogObserverImpl () {
}
#Override
public void onSubscribe(#NonNull Disposable d) {
// TODO Auto-generated method stub
System.out.println("subscribed");
}
#Override
public void onNext(#NonNull List<String> t) {
System.out.println(t.toString());
}
#Override
public void onError(#NonNull Throwable e) {
// TODO Auto-generated method stub
}
#Override
public void onComplete() {
// TODO Auto-generated method stub
System.out.println("finished");
}
}
}
I didnt implement the websocket yet, because my problem lies with observing the changes of
private List<String> currentLog; in the McServerServive class.
Unfortunately I deleted the main method in McServerWebSocket, that I used to test this, but that main method would essentially just create an instance of McServerWebSocket and then call the startWatching() method of its McServerService mss = new McServerService("D:\\Spiele\\Minecraft"); and its
public void subscribeToLog (Observer<? super List<String>> observer) {
this.observableLog.subscribe(observer);
}
method with the inner class:
private class ConsoleLogObserverImpl implements Observer<List<String>>
But the behaviour was not as I would have exspected. The output was:
subscribed
[]
finished
The observable was imediately terminating. Did I do something wrong when creating the Observable or did I completly misunderstand the usage RxJava?
How can I create an Observable class field and an Observer that triggers an action when the Observable is changed with RxJava/some Quarkus extension?
Is there any way to implement AOP logging to public method of class that implements Runnable and ran by ExecutorService?
Thread class
#Component
#Scope("prototype")
public class FileProcessor implements Runnable {
private final LinkedBlockingQueue<File> filesQueue;
private final GiftCertificateMapper certificateMapper;
private final File errorFolder;
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessor.class);
public FileProcessor(LinkedBlockingQueue<File> filesQueue, GiftCertificateMapper certificateMapper,
File errorFolder) {
this.filesQueue = filesQueue;
this.certificateMapper = certificateMapper;
this.errorFolder = errorFolder;
}
#Override
public void run() {
File file = null;
try {
while ((file = filesQueue.poll(100, TimeUnit.MILLISECONDS)) != null) {
processFile(file);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.warn("File thread was interrupted");
} catch (IOException e) {
LOGGER.error("Error processing file {} \n{}", file.getAbsolutePath(), e);
}
}
public void processFile(File file) throws IOException {
if (file != null) {
try {
ObjectMapper objectMapper = new ObjectMapper();
List<GiftCertificate> certificates = Arrays.asList(objectMapper.readValue(file, GiftCertificate[].class));
certificateMapper.insertList(certificates);
file.delete();
} catch (JsonParseException | UnrecognizedPropertyException | InvalidFormatException | DataIntegrityViolationException e) {
moveFileToErrorFolder(file);
}
}
}
private void moveFileToErrorFolder(File file) throws IOException {
try {
LOCK.lock();
Files.move(Paths.get(file.getAbsolutePath()), getPathForMovingFile(file), StandardCopyOption.ATOMIC_MOVE);
} finally {
LOCK.unlock();
}
}
private Path getPathForMovingFile(File fileForMove) {
File fileList[] = errorFolder.listFiles();
int filesWithSameNameCounter = 0;
if (fileList != null && fileList.length > 0) {
for (File file : fileList) {
if (file.getName().contains(fileForMove.getName())) {
filesWithSameNameCounter++;
}
}
}
return filesWithSameNameCounter > 0 ?
Paths.get(errorFolder.getAbsolutePath(), "(" + filesWithSameNameCounter + ")" + fileForMove.getName()) :
Paths.get(errorFolder.getAbsolutePath(), fileForMove.getName());
}
}
Aspect
#Aspect
#Component
#ConditionalOnProperty(
value = "file-processing.logging.enabled",
havingValue = "true",
matchIfMissing = true)
public class FileProcessingLoggingAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessingLoggingAspect.class);
#Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))")
public void processFilePointcut() {
}
#Around("processFilePointcut()")
public Object logFileProcessing(ProceedingJoinPoint joinPoint) throws Throwable {
// File file = (File) joinPoint.getArgs()[0];
// long time = System.currentTimeMillis();
Object object = joinPoint.proceed();
// long resultTime = System.currentTimeMillis() - time;
LOGGER.info("Processing of file took milliseconds");
return object;
}
}
In Spring AOP , internal method calls cannot be intercepted.
In the code shared , even though the method processFile() is public , it gets called from run(). This is a self reference / internal method call , which cannot be intercepted.
Details can be read in the documentation
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are, by definition, not intercepted. For JDK
proxies, only public interface method calls on the proxy can be
intercepted
A pointcut expression to intercept all external method calls to a class implementing Runnable would be as follows
#Around("this(java.lang.Runnable) && within(com.epam.esm.processor..*)")
public Object logFileProcessing(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} finally {
//log
System.out.println("****Logged");
}
}
Scoping designator within() limits the scope to apply the advice.
The point cut #Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))") is valid and would work if an external method call happens to it.
Hope this helps.
There is a need to invoke redraw() method that defined in main class when event fires from different thread that has WatchService. How to make it work?
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
List < String > args = getParameters().getRaw();
Runnable watchFileChangesThread = () -> {
try {
setUpWatchService();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(watchFileChangesThread).start();
//...
}
private void redraw(){//redraw UI}
private void setUpWatchService() throws IOException, InterruptedException {
final Path path = FileSystems.getDefault().getPath(System.getProperty("user.dir"), "");
System.out.println(path);
try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
final WatchKey wk = watchService.take();
for (WatchEvent < ? > event : wk.pollEvents()) {
final Path changed = (Path) event.context();
System.out.println(changed);
if (changed.endsWith("input.txt")) {
System.out.println("My file has changed");
}
}
// reset the key
boolean valid = wk.reset();
if (!valid) {
System.out.println("Key has been unregistered");
}
}
}
}
}
Call Platform.runLater(this::redraw);
I am using a global variables "GlobalVariables" in a separated class and I am try to use it in the following code but it is always gives me the error :
The method getApplication() is undefined for the type UploadPicture
I tried the following but still have error:
((GlobalVariables) this.getApplication()).set_FileUploading(false);
The qustion was already asked here but unfortunatlly all the answors didn't work with me and gave me same error! any suggestion please?
public class UploadPicture extends AsyncTask<Void, Long, Boolean> {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private String mErrorMsg;
private File outFiles;
public UploadPicture(Context context, DropboxAPI<?> api, String dropboxPath, File file) {
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
}
#Override
protected Boolean doInBackground(Void... params) {
try {
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + outFiles.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
return 500;
}
#Override
public void onProgress(long bytes, long total) {
//publishProgress(bytes);
}
}
);
if (mRequest != null) {
mRequest.upload();
((GlobalVariables) UploadPicture.this.getApplication()).set_FileUploading(false);
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return false;
}
}
Edit: I am adding now my "VariableGlobales" calss:
public class GlobalVariables extends Application {
private Boolean _IsIOIORunning=false;
private Boolean _FileUploading=false;
public Boolean get_IsIOIORunning()
{
return _IsIOIORunning;
}
public void set_IsIOIORunning(Boolean _IsIOIORunning)
{
this._IsIOIORunning = _IsIOIORunning;
}
public Boolean get_FileUploading()
{
return _FileUploading;
}
public void set_FileUploading(Boolean _FileUploading)
{
this._FileUploading = _FileUploading;
}
It's normal UploadPicture doesn't extend GlobalVariables but it extend AsyncTask.
That it's my "GlobalVariables "
public class AppInfo extends Application {
private static Context context;
private static String user;
public void onCreate(){
super.onCreate();
AppInfo.context = getApplicationContext();
user = null;
}
public static Context getAppContext() {return AppInfo.context;}
public static String getUser() {return user;}
public static void setUser(String user) {AppInfo.user = user;}
}
And I call it everywhere like that:
AppInfo.getUser();
Edit:
GlobalVariables should use static method and variables:
public class GlobalVariables extends Application {
private static Boolean _IsIOIORunning=false;
private static Boolean _FileUploading=false;
public static Boolean get_IsIOIORunning() {
return _IsIOIORunning;
}
public static void set_IsIOIORunning(Boolean _IsIOIORunning) {
GlobalVariables._IsIOIORunning = _IsIOIORunning;
}
public static Boolean get_FileUploading(){
return _FileUploading;
}
public static void set_FileUploading(Boolean _FileUploading){
GlobalVariables._FileUploading = _FileUploading;
}
}
I want to watch a directory for file changes. And I used WatchService in java.nio. I can successfully listen for file created event. But I can't listen for file modify event. I checked official java tutorial, but still struggling.
Here is the source code.
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class MainWatch {
public static void watchDirectoryPath(Path path) {
// Sanity check - Check if path is a folder
try {
Boolean isFolder = (Boolean) Files.getAttribute(path,
"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder) {
throw new IllegalArgumentException("Path: " + path
+ " is not a folder");
}
} catch (IOException ioe) {
// Folder does not exists
ioe.printStackTrace();
}
System.out.println("Watching path: " + path);
// We obtain the file system of the Path
FileSystem fs = path.getFileSystem();
// We create the new WatchService using the new try() block
try (WatchService service = fs.newWatchService()) {
// We register the path to the service
// We watch for creation events
path.register(service, ENTRY_CREATE);
path.register(service, ENTRY_MODIFY);
path.register(service, ENTRY_DELETE);
// Start the infinite polling loop
WatchKey key = null;
while (true) {
key = service.take();
// Dequeueing events
Kind<?> kind = null;
for (WatchEvent<?> watchEvent : key.pollEvents()) {
// Get the type of the event
kind = watchEvent.kind();
if (OVERFLOW == kind) {
continue; // loop
} else if (ENTRY_CREATE == kind) {
// A new Path was created
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
// Output
System.out.println("New path created: " + newPath);
} else if (ENTRY_MODIFY == kind) {
// modified
Path newPath = ((WatchEvent<Path>) watchEvent)
.context();
// Output
System.out.println("New path modified: " + newPath);
}
}
if (!key.reset()) {
break; // loop
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
public static void main(String[] args) throws IOException,
InterruptedException {
// Folder we are going to watch
// Path folder =
// Paths.get(System.getProperty("C:\\Users\\Isuru\\Downloads"));
File dir = new File("C:\\Users\\Isuru\\Downloads");
watchDirectoryPath(dir.toPath());
}
}
Actually you have incorrectly subscribed to events. Only last listener has been registered with ENTRY_DELETE events type.
To register for all kind of events at once you should use:
path.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
Warning! Shameless self promotion!
I have created a wrapper around Java 1.7's WatchService that allows registering a directory and any number of glob patterns. This class will take care of the filtering and only emit events you are interested in.
DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw
watchService.register( // May throw
new DirectoryWatchService.OnFileChangeListener() {
#Override
public void onFileCreate(String filePath) {
// File created
}
#Override
public void onFileModify(String filePath) {
// File modified
}
#Override
public void onFileDelete(String filePath) {
// File deleted
}
},
<directory>, // Directory to watch
<file-glob-pattern-1>, // E.g. "*.log"
<file-glob-pattern-2>, // E.g. "input-?.txt"
... // As many patterns as you like
);
watchService.start();
Complete code is in this repo.
I made some classes for this.
public interface FileAvailableListener {
public void fileAvailable(File file) throws IOException;
}
and
public class FileChange {
private long lastModified;
private long size;
private long lastCheck;
public FileChange(File file) {
this.lastModified=file.lastModified();
this.size=file.length();
this.lastCheck = System.currentTimeMillis();
}
public long getLastModified() {
return lastModified;
}
public long getSize() {
return size;
}
public long getLastCheck() {
return lastCheck;
}
public boolean isStable(FileChange other,long stableTime) {
boolean b1 = (getLastModified()==other.getLastModified());
boolean b2 = (getSize()==other.getSize());
boolean b3 = ((other.getLastCheck()-getLastCheck())>stableTime);
return b1 && b2 && b3;
}
}
and
public class DirectoryWatcher {
private Timer timer;
private List<DirectoryMonitorTask> tasks = new ArrayList<DirectoryMonitorTask>();
public DirectoryWatcher() throws URISyntaxException, IOException, InterruptedException {
super();
timer = new Timer(true);
}
public void addDirectoryMonitoringTask(DirectoryMonitorTask task,long period) {
tasks.add(task);
timer.scheduleAtFixedRate(task, 5000, period);
}
public List<DirectoryMonitorTask> getTasks() {
return Collections.unmodifiableList(tasks);
}
public Timer getTimer() {
return timer;
}
}
and
class DirectoryMonitorTask extends TimerTask {
public final static String DIRECTORY_NAME_ARCHIVE="archive";
public final static String DIRECTORY_NAME_ERROR="error";
public final static String LOCK_FILE_EXTENSION=".lock";
public final static String ERROR_FILE_EXTENSION=".error";
public final static String FILE_DATE_FORMAT="yyyyMMddHHmmssSSS";
private String name;
private FileAvailableListener listener;
private Path directory;
private File directoryArchive;
private File directoryError;
private long stableTime;
private FileFilter filter;
private WatchService watchService;
private SimpleDateFormat dateFormatter = new SimpleDateFormat(FILE_DATE_FORMAT);
private Hashtable<File,FileChange> fileMonitor = new Hashtable<File,FileChange>();
public DirectoryMonitorTask(String name,FileAvailableListener listener,Path directory,long stableTime,FileFilter filter) throws IOException {
super();
this.name=name;
this.listener=listener;
this.directory=directory;
this.stableTime=stableTime;
if (stableTime<1) {
stableTime=1000;
}
this.filter=filter;
validateNotNull("Name",name);
validateNotNull("Listener",listener);
validateNotNull("Directory",directory);
validate(directory);
directoryArchive = new File(directory.toFile(),DIRECTORY_NAME_ARCHIVE);
directoryError = new File(directory.toFile(),DIRECTORY_NAME_ERROR);
directoryArchive.mkdir();
directoryError.mkdir();
//
log("Constructed for "+getDirectory().toFile().getAbsolutePath());
initialize();
//
watchService = FileSystems.getDefault().newWatchService();
directory.register(watchService,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds.ENTRY_MODIFY);
log("Started");
}
private void initialize() {
File[] files = getDirectory().toFile().listFiles();
for (File file : files) {
if (isLockFile(file)) {
file.delete();
} else if (acceptFile(file)) {
fileMonitor.put(file,new FileChange(file));
log("Init file added -"+file.getName());
}
}
}
public SimpleDateFormat getDateFormatter() {
return dateFormatter;
}
public Path getDirectory() {
return directory;
}
public FileAvailableListener getListener() {
return listener;
}
public String getName() {
return name;
}
public WatchService getWatchService() {
return watchService;
}
public long getStableTime() {
return stableTime;
}
public File getDirectoryArchive() {
return directoryArchive;
}
public File getDirectoryError() {
return directoryError;
}
public FileFilter getFilter() {
return filter;
}
public Iterator<File> getMonitoredFiles() {
return fileMonitor.keySet().iterator();
}
#Override
public void run() {
WatchKey key;
try {
key = getWatchService().take();
// Poll all the events queued for the key
for (WatchEvent<?> event : key.pollEvents()) {
#SuppressWarnings("unchecked")
Path filePath = ((WatchEvent<Path>) event).context();
File file = filePath.toFile();
if ((!isLockFile(file)) && (acceptFile(file))) {
switch (event.kind().name()) {
case "ENTRY_CREATE":
//
fileMonitor.put(file,new FileChange(file));
log("File created ["+file.getName()+"]");
break;
//
case "ENTRY_MODIFY":
//
fileMonitor.put(file,new FileChange(file));
log("File modified ["+file.getName()+"]");
break;
//
case "ENTRY_DELETE":
//
log("File deleted ["+file.getName()+"]");
createLockFile(file).delete();
fileMonitor.remove(file);
break;
//
}
}
}
// reset is invoked to put the key back to ready state
key.reset();
} catch (InterruptedException e) {
e.printStackTrace();
}
Iterator<File> it = fileMonitor.keySet().iterator();
while (it.hasNext()) {
File file = it.next();
FileChange fileChange = fileMonitor.get(file);
FileChange fileChangeCurrent = new FileChange(file);
if (fileChange.isStable(fileChangeCurrent, getStableTime())) {
log("File is stable ["+file.getName()+"]");
String filename = getDateFormatter().format(new Date())+"_"+file.getName();
File lockFile = createLockFile(file);
if (!lockFile.exists()) {
log("File do not has lock file ["+file.getName()+"]");
try {
Files.createFile(lockFile.toPath());
log("Processing file ["+file.getName()+"]");
getListener().fileAvailable(file);
file.renameTo(new File(getDirectoryArchive(),filename));
log("Moved to archive file ["+file.getName()+"]");
} catch (IOException e) {
file.renameTo(new File(getDirectoryError(),filename));
createErrorFile(file,e);
log("Moved to error file ["+file.getName()+"]");
} finally {
lockFile.delete();
}
} else {
log("File do has lock file ["+file.getName()+"]");
fileMonitor.remove(file);
}
} else {
log("File is unstable ["+file.getName()+"]");
fileMonitor.put(file,fileChangeCurrent);
}
}
}
public boolean acceptFile(File file) {
if (getFilter()!=null) {
return getFilter().accept(file);
} else {
return true;
}
}
public boolean isLockFile(File file) {
int pos = file.getName().lastIndexOf('.');
String extension="";
if (pos!=-1) {
extension = file.getName().substring(pos).trim().toLowerCase();
}
return(extension.equalsIgnoreCase(LOCK_FILE_EXTENSION));
}
private File createLockFile(File file) {
return new File(file.getParentFile(),file.getName()+LOCK_FILE_EXTENSION);
}
private void createErrorFile(File file,IOException exception) {
File errorFile = new File(file.getParentFile(),file.getName()+ERROR_FILE_EXTENSION);
StringWriter sw = null;
PrintWriter pw = null;
FileWriter fileWriter = null;
try {
//
fileWriter = new FileWriter(errorFile);
if (exception!=null) {
sw = new StringWriter();
pw = new PrintWriter(sw);
exception.printStackTrace(pw);
fileWriter.write(sw.toString());
} else {
fileWriter.write("Exception is null.");
}
//
fileWriter.flush();
//
} catch (IOException e) {
} finally {
if (sw!=null) {
try {
sw.close();
} catch (IOException e1) {
}
}
if (pw!=null) {
pw.close();
}
if (fileWriter!=null) {
try {
fileWriter.close();
} catch (IOException e) {
}
}
}
}
private void validateNotNull(String name,Object obj) {
if (obj==null) {
throw new NullPointerException(name+" is null.");
}
}
private void validate(Path directory) throws IOException {
File file = directory.toFile();
if (!file.exists()) {
throw new IOException("Directory ["+file.getAbsolutePath()+"] do not exists.");
} else if (!file.isDirectory()) {
throw new IOException("Directory ["+file.getAbsolutePath()+"] is not a directory.");
} else if (!file.canRead()) {
throw new IOException("Can not read from directory ["+file.getAbsolutePath()+"].");
} else if (!file.canWrite()) {
throw new IOException("Can not write to directory ["+file.getAbsolutePath()+"] .");
}
}
private void log(String msg) {
//TODO
System.out.println("Task ["+getName()+"] "+msg);
}
}
package p1;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
public class WatchForFile {
public void WatchMyFolder(String path )
{
File dir = new File(path);
Path myDir= dir.toPath();
try
{
Boolean isFolder = (Boolean) Files.getAttribute(myDir,"basic:isDirectory", NOFOLLOW_LINKS);
if (!isFolder)
{
throw new IllegalArgumentException("Path: " + myDir + " is not a folder");
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
System.out.println("Watching path: " + myDir);
try {
WatchService watcher = myDir.getFileSystem().newWatchService();
myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey watckKey = watcher.take();
List<WatchEvent<?>> events = watckKey.pollEvents();
for (WatchEvent event : events) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
System.out.println("Created: " + event.kind().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("Delete: " + event.context().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("Modify: " + event.context().toString());
}
}
}
catch (Exception e)
{
System.out.println("Error: " + e.toString());
}
}
}
Check this Code...
https://github.com/omkar9999/FileWatcherHandler
This project allows watching files for different file events like create, modify & delete and then act on these events in a generic way.
How to Use?
Create a Path object representing the directory to monitor for file events.
Path path = Paths.get("/home/omkar/test");
Implement the FileHandler interface to perform an action detected by file event registered.
public class FileHandlerTest implements FileHandler {
private static final Logger LOGGER = Logger.getLogger(FileHandlerTest.class.getName());
/*
* This implemented method will delete the file
*
* #see com.io.util.FileHandler#handle(java.io.File,
* java.nio.file.WatchEvent.Kind)
*/
public void handle(File file, Kind<?> fileEvent) {
LOGGER.log(Level.INFO,"Handler is triggered for file {0}",file.getPath());
if(fileEvent == StandardWatchEventKinds.ENTRY_CREATE) {
try {
boolean deleted = Files.deleteIfExists(Paths.get(file.getPath()));
assertTrue(deleted);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Create an instance of an Implemented FileHandler
FileHandlerTest fileHandlerTest = new FileHandlerTest();
Create an instance of a FileWatcher by passing path, an instance of an Implemented FileHandler, and types of file events that you want to monitor separated by commas.
FileWatcher fileWatcher = new FileWatcher(path, fileHandlerTest, StandardWatchEventKinds.ENTRY_CREATE);
Now Create and start a new Thread.
Thread watcherThread = new Thread(fileWatcher);
watcherThread.start();
This thread will start polling for your registered file events and will invoke your custom handle method once any of the registered events are detected.
public class FileWatcher implements Runnable {
private static final Logger LOGGER =Logger.getLogger(FileWatcher.class.getName());
private WatchService watcher;
private FileHandler fileHandler;
private List<Kind<?>> watchedEvents;
private Path directoryWatched;
/**
* #param directory
* #Path directory to watch files into
* #param fileHandler
* #FileHandler implemented instance to handle the file event
* #param watchRecursive
* if directory is to be watched recursively
* #param watchedEvents
* Set of file events watched
*
* #throws IOException
*/
public FileWatcher(Path directory, FileHandler fileHandler, boolean watchRecursive,
WatchEvent.Kind<?>... watchedEvents) throws IOException {
super();
this.watcher = FileSystems.getDefault().newWatchService();
this.fileHandler = fileHandler;
this.directoryWatched = directory;
this.watchedEvents = Arrays.asList(watchedEvents);
if (watchRecursive) {
// register all subfolders
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
LOGGER.log(Level.INFO, "Registering {0} ", dir);
dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
return FileVisitResult.CONTINUE;
}
});
} else {
directory.register(watcher, watchedEvents);
}
}
#SuppressWarnings({ "unchecked" })
public void run() {
LOGGER.log(Level.INFO, "Starting FileWatcher for {0}", directoryWatched.toAbsolutePath());
WatchKey key = null;
while (true) {
try {
key = watcher.take();
if (key != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
WatchEvent<Path> ev = (WatchEvent<Path>) event;
//directory in which file event is detected
Path directory = (Path) key.watchable();
Path fileName = ev.context();
if (watchedEvents.contains(kind)) {
LOGGER.log(Level.INFO, "Invoking handle on {0}", fileName.toAbsolutePath());
fileHandler.handle(directory.resolve(fileName).toFile(), kind);
}
}
key.reset();
}
} catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Polling Thread was interrupted ", ex);
Thread.currentThread().interrupt();
}
}
}
}