it.geosolutions.tools.io.file.FileRemover.java Source code

Java tutorial

Introduction

Here is the source code for it.geosolutions.tools.io.file.FileRemover.java

Source

/*
 * Copyright (C) 2011 - 2012  GeoSolutions S.A.S.
 * http://www.geo-solutions.it
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package it.geosolutions.tools.io.file;

import it.geosolutions.tools.commons.Conf;
import it.geosolutions.tools.commons.file.Path;

import java.io.File;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.filefilter.FileFilterUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Simple class implementing a Thread that periodically tries to delete the
 * files that were provided to him.
 * <p>
 * It tries to delete each file at most {@link FileRemover#maxAttempts} number
 * of times. If this number is exceeded it simply throws the file away notifying
 * the users with a warning message.
 * 
 * @author Simone Giannecchini, GeoSolutions.
 * 
 * @deprecated Use FileGarbageCollector instead
 */
public final class FileRemover extends Thread {

    private final static Logger LOGGER = LoggerFactory.getLogger(Path.class.toString());

    private final static Map<String, Integer> FILE_ATTEMPTS_COUNTS = Collections
            .synchronizedMap(new HashMap<String, Integer>());

    /**
     * Maximum number of attempts to delete a given {@link File}.
     * 
     * <p>
     * If the provided number of attempts is exceeded we simply drop warn the
     * user and we remove the {@link File} from our list.
     */
    private int maxAttempts = Conf.DEF_MAX_ATTEMPTS;

    /**
     * Period in seconds between two checks.
     */
    private volatile long period = Conf.DEFAULT_PERIOD;

    private final static Set<String> FILES_PATH = Collections.synchronizedSet(new HashSet<String>());

    public static List<File> collectOlder(final long time, final int daysAgo, final File root) {
        if (daysAgo < 0) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        int days = cal.get(Calendar.DAY_OF_YEAR);
        if (days >= daysAgo)
            cal.set(Calendar.DAY_OF_YEAR, days - daysAgo);
        else {
            // TODO use getActualMaximum for days
            cal.set(Calendar.DAY_OF_YEAR, (354 + (days - daysAgo)));
            cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - 1);
        }
        // cal.getTime().toString()
        final Collector coll = new Collector(FileFilterUtils.andFileFilter(FileFilterUtils.directoryFileFilter(),
                FileFilterUtils.ageFileFilter(cal.getTime(), true)), 1);
        return coll.collect(root);
    }

    /**
     * Asks this {@link FileRemover} to clean up this file.
     * 
     * @param fileToDelete
     *            {@link File} that we want to permanently delete.
     */
    public void addFile(final File fileToDelete) {
        // does it exists
        if (!fileToDelete.exists())
            return;
        synchronized (FILES_PATH) {
            synchronized (FILE_ATTEMPTS_COUNTS) {
                // /////////////////////////////////////////////////////////////////
                //
                // We add the file to our lists for later check.
                //
                // /////////////////////////////////////////////////////////////////
                if (!FILES_PATH.contains(fileToDelete.getAbsolutePath())) {
                    FILES_PATH.add(fileToDelete.getAbsolutePath());
                    FILE_ATTEMPTS_COUNTS.put(fileToDelete.getAbsolutePath(), new Integer(0));

                }
            }
        }
    }

    /**
     * Default constructor for a {@link FileRemover}.
     */
    public FileRemover() {
        this(Conf.DEFAULT_PERIOD, Thread.NORM_PRIORITY - 3, Conf.DEF_MAX_ATTEMPTS);
    }

    /**
     * Constructor for a {@link FileRemover}.
     * 
     * @param period
     *            default time period between two cycles.
     * @param priority
     *            is the priority for the cleaner thread.
     * @param maxattempts
     *            maximum number of time the cleaner thread tries to delete a
     *            file.
     */
    public FileRemover(long period, int priority, int maxattempts) {
        this.period = period;
        this.setName("FileRemover");
        this.setPriority(priority);
        this.setDaemon(true);
        this.maxAttempts = maxattempts;
    }

    /**
     * This method does the magic:
     * 
     * <ol>
     * <li>iterate over all the files</li>
     * <li>try to delete it</li>
     * <li>if successful drop the file references</li>
     * <li>if not successful increase the attempts count for the file and call
     * the gc. If the maximum number was exceeded drop the file and warn the
     * user</li>
     * 
     */
    public void run() {
        while (true) {
            try {
                synchronized (FILES_PATH) {
                    synchronized (FILE_ATTEMPTS_COUNTS) {

                        final Iterator<String> it = FILES_PATH.iterator();
                        while (it.hasNext()) {

                            // get next file path and its count
                            final String sFile = it.next();
                            if (LOGGER.isInfoEnabled())
                                LOGGER.info("Trying to remove file " + sFile);
                            int attempts = FILE_ATTEMPTS_COUNTS.get(sFile).intValue();
                            if (!new File(sFile).exists()) {
                                it.remove();
                                FILE_ATTEMPTS_COUNTS.remove(sFile);
                            } else {
                                // try to delete it
                                if (new File(sFile).delete()) {
                                    if (LOGGER.isInfoEnabled())
                                        LOGGER.info("Successfully removed file " + sFile);
                                    it.remove();
                                    FILE_ATTEMPTS_COUNTS.remove(sFile);
                                } else {
                                    if (LOGGER.isInfoEnabled())
                                        LOGGER.info("Unable to  remove file " + sFile);
                                    attempts++;
                                    if (maxAttempts < attempts) {
                                        if (LOGGER.isInfoEnabled())
                                            LOGGER.info("Dropping file " + sFile);
                                        it.remove();
                                        FILE_ATTEMPTS_COUNTS.remove(sFile);
                                        if (LOGGER.isWarnEnabled())
                                            LOGGER.warn("Unable to delete file " + sFile);
                                    } else {
                                        FILE_ATTEMPTS_COUNTS.remove(sFile);
                                        FILE_ATTEMPTS_COUNTS.put(sFile, new Integer(attempts));
                                        // might help, see
                                        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154
                                        Runtime.getRuntime().gc();
                                        Runtime.getRuntime().gc();
                                        Runtime.getRuntime().gc();
                                        Runtime.getRuntime().gc();
                                        Runtime.getRuntime().gc();
                                        Runtime.getRuntime().gc();
                                        System.runFinalization();
                                        System.runFinalization();
                                        System.runFinalization();
                                        System.runFinalization();
                                        System.runFinalization();
                                        System.runFinalization();

                                    }
                                }
                            }
                        }
                    }
                }
                Thread.sleep(period * 1000);

            } catch (Throwable t) {
                if (LOGGER.isInfoEnabled())
                    LOGGER.info(t.getLocalizedMessage(), t);
            }
        }
    }

    /**
     * Retrieves the maximum number of times we try to delete a file before
     * giving up.
     * 
     * @return the maximum number of times we try to delete a file before giving
     *         up.
     * 
     */
    public int getMaxAttempts() {
        synchronized (FILES_PATH) {
            synchronized (FILE_ATTEMPTS_COUNTS) {
                return maxAttempts;
            }
        }

    }

    /**
     * Sets the maximum number of times we try to delete a file before giving
     * up.
     * 
     * @param maxAttempts
     *            the maximum number of times we try to delete a file before
     *            giving up.
     * 
     */
    public void setMaxAttempts(int maxAttempts) {
        synchronized (FILES_PATH) {
            synchronized (FILE_ATTEMPTS_COUNTS) {
                this.maxAttempts = maxAttempts;
            }
        }

    }

    /**
     * Retrieves the period in seconds for this {@link FileRemover} .
     * 
     * @return the period in seconds for this {@link FileRemover} .
     * 
     */
    public long getPeriod() {
        return period;
    }

    /**
     * Sets the period in seconds for this {@link FileRemover} .
     * 
     * @param period
     *            the new period for this {@link FileRemover} .
     * 
     */
    public void setPeriod(long period) {
        this.period = period;
    }

}