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