deleteFailures = Collections.synchronizedList(new ArrayList<>());
/**
* Whether to terminate the thread when the tracking is complete.
*/
volatile boolean exitWhenFinished;
/**
* The thread that will clean up registered files.
*/
Thread reaper;
/**
* Adds a tracker to the list of trackers.
*
* @param path the full path to the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
*/
private synchronized void addTracker(final String path, final Object marker, final FileDeleteStrategy
deleteStrategy) {
// synchronized block protects reaper
if (exitWhenFinished) {
throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
}
if (reaper == null) {
reaper = new Reaper();
reaper.start();
}
trackers.add(new Tracker(path, deleteStrategy, marker, q));
}
/**
* Call this method to cause the file cleaner thread to terminate when
* there are no more objects being tracked for deletion.
*
* In a simple environment, you don't need this method as the file cleaner
* thread will simply exit when the JVM exits. In a more complex environment,
* with multiple class loaders (such as an application server), you should be
* aware that the file cleaner thread will continue running even if the class
* loader it was started from terminates. This can constitute a memory leak.
*
* For example, suppose that you have developed a web application, which
* contains the commons-io jar file in your WEB-INF/lib directory. In other
* words, the FileCleaner class is loaded through the class loader of your
* web application. If the web application is terminated, but the servlet
* container is still running, then the file cleaner thread will still exist,
* posing a memory leak.
*
* This method allows the thread to be terminated. Simply call this method
* in the resource cleanup code, such as
* {@code javax.servlet.ServletContextListener.contextDestroyed(javax.servlet.ServletContextEvent)}.
* Once called, no new objects can be tracked by the file cleaner.
*/
public synchronized void exitWhenFinished() {
// synchronized block protects reaper
exitWhenFinished = true;
if (reaper != null) {
synchronized (reaper) {
reaper.interrupt();
}
}
}
/**
* Gets a copy of the file paths that failed to delete.
*
* @return a copy of the file paths that failed to delete
* @since 2.0
*/
public List getDeleteFailures() {
return new ArrayList<>(deleteFailures);
}
/**
* Gets the number of files currently being tracked, and therefore
* awaiting deletion.
*
* @return the number of files being tracked
*/
public int getTrackCount() {
return trackers.size();
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
*
* @param file the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @throws NullPointerException if the file is null
*/
public void track(final File file, final Object marker) {
track(file, marker, null);
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The specified deletion strategy is used.
*
* @param file the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
* @throws NullPointerException if the file is null
*/
public void track(final File file, final Object marker, final FileDeleteStrategy deleteStrategy) {
Objects.requireNonNull(file, "file");
addTracker(file.getPath(), marker, deleteStrategy);
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
*
* @param file the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @throws NullPointerException if the file is null
* @since 2.14.0
*/
public void track(final Path file, final Object marker) {
track(file, marker, null);
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The specified deletion strategy is used.
*
* @param file the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
* @throws NullPointerException if the file is null
* @since 2.14.0
*/
public void track(final Path file, final Object marker, final FileDeleteStrategy deleteStrategy) {
Objects.requireNonNull(file, "file");
addTracker(file.toAbsolutePath().toString(), marker, deleteStrategy);
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
*
* @param path the full path to the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @throws NullPointerException if the path is null
*/
public void track(final String path, final Object marker) {
track(path, marker, null);
}
/**
* Tracks the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The specified deletion strategy is used.
*
* @param path the full path to the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
* @throws NullPointerException if the path is null
*/
public void track(final String path, final Object marker, final FileDeleteStrategy deleteStrategy) {
Objects.requireNonNull(path, "path");
addTracker(path, marker, deleteStrategy);
}
}