Issue invoking WatchService inside a singleton bean - java

we wanted to watch a file periodically for changes, we are using jboss 7 . Following is my code snippet. I initialized the watcher in the postconstruct method of singleton bean and scheduled a method to poll watch events. I could observe the changes when i modify the file very first time, however the subsequent modifications to the file are not recieved . Can anyone please let me know what could be the issue
#Startup
#ConcurrencyManagement(ConcurrencyManagementType.BEAN)
#Interceptors(NonThrowingPostConstructInterceptor.class)
#Singleton
#Service
#LocalBinding(jndiBinding=IHeartBeatProducerService.JNDI_LOCAL_BINDING)
public class HeartBeatProducerService extends EMSingletonService implements IHeartBeatProducerService{
#EJB(mappedName=IMessageService.JNDI_LOCAL_BINDING)
public IMessageService messageService;
#EJB(mappedName=ICommandExecutionService.JNDI_LOCAL_BINDING)
public ICommandExecutionService commandService;
private final static String LAST_OPERATION_COMPLETED="Last Operation Completed";
private final static String STATUS="Status";
private WatchService watcher;
private Path dir;
private String concServer;
public static final String TOPIC="foo";
private IMLogger logger = new IMLogger("foo");
private String content=null;
#PostConstruct
#Override
public void init() {
// TODO Auto-generated method stub
super.init();
try {
watcher = FileSystems.getDefault().newWatchService();
dir=Paths.get("/shared/foo");
dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Initializing Heart Beat", new String[]{"Entered"});
} catch (IOException e) {
e.printStackTrace();
}
}
#Schedule(second="*/10", minute = "*", hour="*")
private void checkStatus()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Checking Status", new String[]{"Entered"});
final String[] command={"pidof","server"};
commandService.run(command, null, false);
concServer=(commandService.getExitCode()==0)?"UP":"DOWN";
if(concServer.equals("UP"))
{
watch();
}
else
{
content="foo:Failed";
}
produce();
}
public void watch()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Entering watch()", new String[]{"Entered"});
WatchKey key = null;
try
{
key = watcher.take();
}
catch (InterruptedException e)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Interupted Exception " + e.getMessage());
}
for ( WatchEvent<?> event: key.pollEvents())
{
WatchEvent.Kind kind = event.kind();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Watch Event :" + kind.name());
if(kind.name().equals("OVERFLOW"))
{
continue;
}
if(kind.name().equals("ENTRY_MODIFY"))
{
Path concLog = (Path) event.context();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Modified File Name:" + concLog.getFileName());
if(concLog.endsWith("current_status.txt"))
{
logger.info(HeartBeatProducerService.class.getSimpleName(), "Reading Status");
readStatus();
}
}
}
boolean valid = key.reset();
if ( !valid)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Key Unregistered");
}
}
private void parse(String output)
{
// parse file contents
}
private void readStatus() {
//read status and parse()
}
private void produce()
{
try {
messageService.publish(TOPIC, content, PublishType.ASync);
} catch (MessageException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
There is already a link explaining the same with #Asynchronous tag (EJB 3.1 and NIO2: Monitoring the file system) . however I need to know what could be wrong in this approach.

Your watch method needs to run in an infinite loop. What's happening now is that after
try {
key = watcher.take();
}
you process the event and then the watch() method is finished. Try the effect of
for(;;) {
before the above lines, ending the for block after the validity check. Did you see the example at The Java Tutorials?

Related

Observer with RxJava/Quarkus

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?

Spring AOP logging thread method

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.

How to invoke method in main thread from thread that is used as WatchService?

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);

The method getApplication() is undefined for the type (my class)

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;
}
}

Watching a Directory for Changes in Java

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();
}
}
}
}

Categories