001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io;
018
019import java.io.File;
020import java.io.IOException;
021
022/**
023 * Strategy for deleting files.
024 * <p>
025 * There is more than one way to delete a file.
026 * You may want to limit access to certain directories, to only delete
027 * directories if they are empty, or maybe to force deletion.
028 * <p>
029 * This class captures the strategy to use and is designed for user subclassing.
030 *
031 * @version $Id: FileDeleteStrategy.java 1563227 2014-01-31 19:45:30Z ggregory $
032 * @since 1.3
033 */
034public class FileDeleteStrategy {
035
036    /**
037     * The singleton instance for normal file deletion, which does not permit
038     * the deletion of directories that are not empty.
039     */
040    public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal");
041    /**
042     * The singleton instance for forced file deletion, which always deletes,
043     * even if the file represents a non-empty directory.
044     */
045    public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy();
046
047    /** The name of the strategy. */
048    private final String name;
049
050    //-----------------------------------------------------------------------
051    /**
052     * Restricted constructor.
053     *
054     * @param name  the name by which the strategy is known
055     */
056    protected FileDeleteStrategy(final String name) {
057        this.name = name;
058    }
059
060    //-----------------------------------------------------------------------
061    /**
062     * Deletes the file object, which may be a file or a directory.
063     * All <code>IOException</code>s are caught and false returned instead.
064     * If the file does not exist or is null, true is returned.
065     * <p>
066     * Subclass writers should override {@link #doDelete(File)}, not this method.
067     *
068     * @param fileToDelete  the file to delete, null returns true
069     * @return true if the file was deleted, or there was no such file
070     */
071    public boolean deleteQuietly(final File fileToDelete) {
072        if (fileToDelete == null || fileToDelete.exists() == false) {
073            return true;
074        }
075        try {
076            return doDelete(fileToDelete);
077        } catch (final IOException ex) {
078            return false;
079        }
080    }
081
082    /**
083     * Deletes the file object, which may be a file or a directory.
084     * If the file does not exist, the method just returns.
085     * <p>
086     * Subclass writers should override {@link #doDelete(File)}, not this method.
087     *
088     * @param fileToDelete  the file to delete, not null
089     * @throws NullPointerException if the file is null
090     * @throws IOException if an error occurs during file deletion
091     */
092    public void delete(final File fileToDelete) throws IOException {
093        if (fileToDelete.exists() && doDelete(fileToDelete) == false) {
094            throw new IOException("Deletion failed: " + fileToDelete);
095        }
096    }
097
098    /**
099     * Actually deletes the file object, which may be a file or a directory.
100     * <p>
101     * This method is designed for subclasses to override.
102     * The implementation may return either false or an <code>IOException</code>
103     * when deletion fails. The {@link #delete(File)} and {@link #deleteQuietly(File)}
104     * methods will handle either response appropriately.
105     * A check has been made to ensure that the file will exist.
106     * <p>
107     * This implementation uses {@link File#delete()}.
108     *
109     * @param fileToDelete  the file to delete, exists, not null
110     * @return true if the file was deleteds
111     * @throws NullPointerException if the file is null
112     * @throws IOException if an error occurs during file deletion
113     */
114    protected boolean doDelete(final File fileToDelete) throws IOException {
115        return fileToDelete.delete();
116    }
117
118    //-----------------------------------------------------------------------
119    /**
120     * Gets a string describing the delete strategy.
121     *
122     * @return a string describing the delete strategy
123     */
124    @Override
125    public String toString() {
126        return "FileDeleteStrategy[" + name + "]";
127    }
128
129    //-----------------------------------------------------------------------
130    /**
131     * Force file deletion strategy.
132     */
133    static class ForceFileDeleteStrategy extends FileDeleteStrategy {
134        /** Default Constructor */
135        ForceFileDeleteStrategy() {
136            super("Force");
137        }
138
139        /**
140         * Deletes the file object.
141         * <p>
142         * This implementation uses <code>FileUtils.forceDelete()</code>
143         * if the file exists.
144         *
145         * @param fileToDelete  the file to delete, not null
146         * @return Always returns {@code true}
147         * @throws NullPointerException if the file is null
148         * @throws IOException if an error occurs during file deletion
149         */
150        @Override
151        protected boolean doDelete(final File fileToDelete) throws IOException {
152            FileUtils.forceDelete(fileToDelete);
153            return true;
154        }
155    }
156
157}