14fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/* 24fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Licensed to the Apache Software Foundation (ASF) under one or more 34fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * contributor license agreements. See the NOTICE file distributed with 44fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * this work for additional information regarding copyright ownership. 54fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The ASF licenses this file to You under the Apache License, Version 2.0 64fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * (the "License"); you may not use this file except in compliance with 74fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * the License. You may obtain a copy of the License at 84fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 94fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * http://www.apache.org/licenses/LICENSE-2.0 104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Unless required by applicable law or agreed to in writing, software 124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * distributed under the License is distributed on an "AS IS" BASIS, 134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * See the License for the specific language governing permissions and 154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * limitations under the License. 164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypackage org.apache.commons.io; 184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.io.File; 204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.lang.ref.PhantomReference; 214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.lang.ref.ReferenceQueue; 224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.Collection; 234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.Vector; 244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/** 264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Keeps track of files awaiting deletion, and deletes them when an associated 274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * marker object is reclaimed by the garbage collector. 284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p> 294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This utility creates a background thread to handle file deletion. 304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Each file to be deleted is registered with a handler object. 314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * When the handler object is garbage collected, the file is deleted. 324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p> 334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * In an environment with multiple class loaders (a servlet container, for 344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * example), you should consider stopping the background thread if it is no 354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * longer needed. This is done by invoking the method 364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * {@link #exitWhenFinished}, typically in 374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar. 384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author Noel Bergman 404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @author Martin Cooper 414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $ 424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypublic class FileCleaningTracker { 444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Queue of <code>Tracker</code> instances being watched. 464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy ReferenceQueue<Object> /* Tracker */ q = new ReferenceQueue<Object>(); 484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Collection of <code>Tracker</code> instances in existence. 504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy final Collection<Tracker> /* Tracker */ trackers = new Vector<Tracker>(); // synchronized 524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Whether to terminate the thread when the tracking is complete. 544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy volatile boolean exitWhenFinished = false; 564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The thread that will clean up registered files. 584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy Thread reaper; 604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy //----------------------------------------------------------------------- 624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Track the specified file, using the provided marker, deleting the file 644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * when the marker instance is garbage collected. 654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. 664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param file the file to be tracked, not null 684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @throws NullPointerException if the file is null 704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public void track(File file, Object marker) { 724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy track(file, marker, (FileDeleteStrategy) null); 734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Track the specified file, using the provided marker, deleting the file 774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * when the marker instance is garbage collected. 784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The speified deletion strategy is used. 794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param file the file to be tracked, not null 814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param deleteStrategy the strategy to delete the file, null means normal 834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @throws NullPointerException if the file is null 844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) { 864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (file == null) { 874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy throw new NullPointerException("The file must not be null"); 884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy addTracker(file.getPath(), marker, deleteStrategy); 904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Track the specified file, using the provided marker, deleting the file 944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * when the marker instance is garbage collected. 954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used. 964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param path the full path to the file to be tracked, not null 984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @throws NullPointerException if the path is null 1004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public void track(String path, Object marker) { 1024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy track(path, marker, (FileDeleteStrategy) null); 1034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Track the specified file, using the provided marker, deleting the file 1074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * when the marker instance is garbage collected. 1084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The speified deletion strategy is used. 1094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 1104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param path the full path to the file to be tracked, not null 1114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 1124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param deleteStrategy the strategy to delete the file, null means normal 1134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @throws NullPointerException if the path is null 1144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) { 1164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (path == null) { 1174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy throw new NullPointerException("The path must not be null"); 1184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy addTracker(path, marker, deleteStrategy); 1204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Adds a tracker to the list of trackers. 1244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 1254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param path the full path to the file to be tracked, not null 1264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 1274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param deleteStrategy the strategy to delete the file, null means normal 1284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) { 1304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy // synchronized block protects reaper 1314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (exitWhenFinished) { 1324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called"); 1334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (reaper == null) { 1354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy reaper = new Reaper(); 1364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy reaper.start(); 1374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy trackers.add(new Tracker(path, deleteStrategy, marker, q)); 1394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy //----------------------------------------------------------------------- 1424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Retrieve the number of files currently being tracked, and therefore 1444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * awaiting deletion. 1454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 1464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @return the number of files being tracked 1474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public int getTrackCount() { 1494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy return trackers.size(); 1504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Call this method to cause the file cleaner thread to terminate when 1544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * there are no more objects being tracked for deletion. 1554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p> 1564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * In a simple environment, you don't need this method as the file cleaner 1574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * thread will simply exit when the JVM exits. In a more complex environment, 1584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * with multiple class loaders (such as an application server), you should be 1594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * aware that the file cleaner thread will continue running even if the class 1604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * loader it was started from terminates. This can consitute a memory leak. 1614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p> 1624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * For example, suppose that you have developed a web application, which 1634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * contains the commons-io jar file in your WEB-INF/lib directory. In other 1644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * words, the FileCleaner class is loaded through the class loader of your 1654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * web application. If the web application is terminated, but the servlet 1664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * container is still running, then the file cleaner thread will still exist, 1674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * posing a memory leak. 1684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <p> 1694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * This method allows the thread to be terminated. Simply call this method 1704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}. 1714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * One called, no new objects can be tracked by the file cleaner. 1724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public synchronized void exitWhenFinished() { 1744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy // synchronized block protects reaper 1754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy exitWhenFinished = true; 1764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (reaper != null) { 1774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy synchronized (reaper) { 1784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy reaper.interrupt(); 1794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy //----------------------------------------------------------------------- 1844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The reaper thread. 1864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy private final class Reaper extends Thread { 1884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** Construct a new Reaper */ 1894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy Reaper() { 1904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy super("File Reaper"); 1914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy setPriority(Thread.MAX_PRIORITY); 1924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy setDaemon(true); 1934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 1944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 1954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 1964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Run the reaper thread that will delete files as their associated 1974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * marker objects are reclaimed by the garbage collector. 1984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 1994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy @Override 2004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public void run() { 2014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy // thread exits when exitWhenFinished is true and there are no more tracked objects 2024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy while (exitWhenFinished == false || trackers.size() > 0) { 2034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy Tracker tracker = null; 2044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy try { 2054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy // Wait for a tracker to remove. 2064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy tracker = (Tracker) q.remove(); 2074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } catch (Exception e) { 2084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy continue; 2094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy if (tracker != null) { 2114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy tracker.delete(); 2124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy tracker.clear(); 2134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy trackers.remove(tracker); 2144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 2194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy //----------------------------------------------------------------------- 2204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 2214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Inner class which acts as the reference for a file pending deletion. 2224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 2234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy private static final class Tracker extends PhantomReference<Object> { 2244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 2254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 2264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The full path to the file being tracked. 2274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 2284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy private final String path; 2294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 2304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * The strategy for deleting files. 2314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 2324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy private final FileDeleteStrategy deleteStrategy; 2334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 2344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 2354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Constructs an instance of this class from the supplied parameters. 2364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 2374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param path the full path to the file to be tracked, not null 2384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param deleteStrategy the strategy to delete the file, null means normal 2394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param marker the marker object used to track the file, not null 2404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @param queue the queue on to which the tracker will be pushed, not null 2414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 2424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue<Object> queue) { 2434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy super(marker, queue); 2444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy this.path = path; 2454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy); 2464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 2484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy /** 2494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Deletes the file associated with this tracker instance. 2504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * 2514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * @return <code>true</code> if the file was deleted successfully; 2524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * <code>false</code> otherwise. 2534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */ 2544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy public boolean delete() { 2554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy return deleteStrategy.deleteQuietly(new File(path)); 2564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy } 2584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy 2594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy} 260