Why is feature X only supported on Platform Y?
jpathwatch uses the native OS’s file watching capabilities so it doesn’t need to use polling to monitor a directory for changes. Different host platforms offer a different set of monitoring capabilies, ranging from very limited (‘something in this directory has changed since you last checked’ on FreeBSD) to pretty good (‘in your watched directory, file A was renamed to B’ on Linux) to exhaustive (‘File a/b/C was moved to subdirectory d/e and renamed to F’ on Windows)
Why does jpathwatch not use a listener interface (observer pattern)?
Listeners are good for single threaded code, like Swing UI handlers. However, because of it’s nature, file watching often needs to be done in a separate thread, which is why Sun designed the WatchService interface like it is (and this is what jpathwatch implements).
However, it is very easy to wrap a listener interface around jpathwatch if desired.
When will platform X be supported natively?
This mainly depends on whether
- The target platform has native file watching support
- We can get a machine to develop and test the library on
What’s all this business about Java 7 and jpathwatch?
The upcoming Java 7 will also offer a file monitoring service. However, at time of writing it only supported Windows and Linux and only offered limited functionality.
jpatchwatch implements Java 7’s API for directory monitoring. The main reasons are:
- There are other file watching libraries around. Yet another API doesn’t make the world a better place.
- Sun’s WatchService API is well designed and thread-safe.
- Easy porting to Java 7 if desired because jpatchwatch is source compatible.
How many directories can I watch?
There generally is no upper limit to the number of directories you can monitor with jpathwatch. However, directory watching does consume system resources; how much greatly depends on the host operating system and the WatchService implementation for that operating system.
It is advisable to use a single WatchService to monitor multiple directories, because the resources required for watching are bundled within the WatchService instance. Also note that if jpathwatch has to fall back to polling it will consume much more resources than if it can use the OS to do the work (see the Features page for more information when jpathwatch uses polling; on most OS’s it will not poll).
Can I use jpathwatch to find out when a program finished writing to a file?
This is a bit tricky, but doable. First of all the problem is that most operating systems do not provide events for that, all they report is if a file has been created, modified or deleted in a directory, which is what jpathwatch passes back to your application code.
So effectively, you can find out when a program writes to a file, but you can’t find out when it’s done with it.
What I recommend in this case is to use heuristics: Assume that a process is done writing to a file when the file isn’t modified for a while (say, ten seconds or so).
Assume you watch a directory on an FTP server, and you want to pick up files after they have finished uploading to that directory.
In a loop, you poll() on the WatchService for events on that directory. For each file that is created or modified (ENTRY_CREATE/ENTRY_MODIFY), you store the time of the last event on that file. Maintain a sorted list of these times; the oldest file in the list is the one that is going to expire first. Remove files that have expired from your sorted list (calculate if their last event time plus the timeout is less than the current time) and flag them as ‘done’.
For the now oldest file in your list that hasn’t expired yet, calculate the time until it will expire, and call poll() with that duration. If you have no more files in your list, call take() instead of poll() to wait for new files to appear.
I get an UnsatisfiedLinkError – [native library] already loaded in another classloader – how can I resolve this?
You might get this exception when you try to use jpathwatch in a multi-classloader environment, like an application server (Tomcat, Glassfish, etc..). Typically this exception is thrown when you try to redeploy your application.
To understand what happens, let’s look at how such an application is loaded: When the the JVM loads the first class of your program, it looks at the other classes that are referenced by your class. Eventually, the JVM will reach jpathwatch, and load its classes.
The JVM doesn’t just load classes, it uses a special object to do the work: A ClassLoader. Typically, a multi-classloader will create a new ClassLoader for each application it loads. Even when an application is unloaded and then loaded again (redeploy), a new ClassLoader will be created.
The issue is now that native libraries, such as the ones jpathwatch uses, are bound to a specific ClassLoader. You also cannot load the same native library twice (even in a different ClassLoader). But the exception you get indicates that this is exactly what’s happening. Usually this situation occurs when the old ClassLoader holding the native library hasn’t been finalized yet (collected by the garbage collector), so the native library is still in memory while the new ClassLoader is attempting to load it.
To safely avoid this issue, you’ll have to make sure that the jpathwatch classes are loaded by a ClassLoader that will never go out of scope, like the system class loader (you can get it by calling ClassLoader.getSystemClassLoader()). How to go about that exactly depends on your environment (i.e. your application server).