/** * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @author Arne Kepp, The Open Planning Project, Copyright 2008 * */ package org.geowebcache.util; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class FileUtils { private static Log log = LogFactory.getLog(org.geowebcache.util.FileUtils.class); static public boolean rmFileCacheDir(File path, ExtensionFileLister extfl) { if (path.exists()) { File[] files = null; if (extfl != null) { files = path.listFiles(extfl); } else { files = path.listFiles(); } for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { rmFileCacheDir(files[i], extfl); } else { if (!files[i].delete()) { log.error("Unable to delete " + files[i].getAbsolutePath()); } } } } return (path.delete()); } /** * Traverses the directory denoted by {@code path} recursively and calls {@code filter.accept} * on each child, files first, subdirectories next. * <p> * For a child directory to be traversed, the {@code filter.accept(File)} method shall have * returned {@code true}, otherwise the child directory is skipped. * </p> * <p> * This method guarantees that {@code filter.accept} will be called first for all files in a * directory and then for all it's sub directories. * <p> * * @param path * @param filter * used to implement the visitor pattern. The accept method may contain any desired * logic, it will be called for all files and directories inside {@code path}, * recursively */ public static void traverseDepth(final File path, final FileFilter filter) { if (path == null) { throw new NullPointerException("path"); } if (filter == null) { throw new NullPointerException("filter"); } if (!path.exists() || !path.isDirectory() || !path.canRead()) { throw new IllegalArgumentException(path.getAbsolutePath() + " either does not exist, or is not a readable directory"); } // Use path.list() instead of path.listFiles() to avoid the simultaneous creation of // thousands of File objects as well as its String objects for the path name. Faster and // less resource intensive String[] fileNames = path.list(); List<File> subDirectories = new ArrayList<File>(); File file; for (int i = 0; i < fileNames.length; i++) { file = new File(path, fileNames[i]); if(file.isDirectory()){ subDirectories.add(file); } filter.accept(file); } if (subDirectories.size() > 0) { for (File subdir : subDirectories) { boolean accepted = filter.accept(subdir); if (accepted && subdir.isDirectory()) { traverseDepth(subdir, filter); } } } } /** * Utility method for renaming Files using Java 7 {@link Files}.move() method * which provides an atomical file renaming. If an exception occurred during the * renaming, the method will fallback to the old File().renameTo() method and * will log a Message. * * @return a boolean indicating if the rename operation has succeded */ public static boolean renameFile(File src, File dst){ // Renaming result initialization boolean renamed = false; // 1) try with Java 7 Files.move Path srcPath = Paths.get(src.toURI()); Path dstPath = Paths.get(dst.toURI()); Path moved = null; try{ // Execute renaming moved = Files.move(srcPath, dstPath, StandardCopyOption.ATOMIC_MOVE); } catch (Exception e){ // Exception occurred falling back to the old renameTo if(log.isDebugEnabled()){ log.debug("An error occurred when executing atomic file renaming. Falling back to the old File.renameTo() method", e); } } // 2) Check if succeeded. If failed, falling back to old renameTo if(moved == null || !Files.exists(moved)){ renamed = src.renameTo(dst); } else { renamed = true; } return renamed; } public static class ExtensionFileLister implements FilenameFilter { private String prefix; private String extension; public ExtensionFileLister(String prefix, String extension) { this.prefix = prefix; this.extension = extension == null ? null : "." + extension; } public boolean accept(File directory, String filename) { if (prefix != null && !filename.startsWith(prefix)) { return false; } if (extension != null) { return filename.endsWith(extension); } return true; } } }