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 */ 017 package org.apache.camel.util; 018 019 import java.io.File; 020 import java.io.IOException; 021 import java.util.Iterator; 022 import java.util.Locale; 023 import java.util.Stack; 024 025 /** 026 * File utilities 027 */ 028 public final class FileUtil { 029 030 private static final int RETRY_SLEEP_MILLIS = 10; 031 private static File defaultTempDir; 032 033 private FileUtil() { 034 } 035 036 /** 037 * Normalizes the path to cater for Windows and other platforms 038 */ 039 public static String normalizePath(String path) { 040 // special handling for Windows where we need to convert / to \\ 041 if (path != null && System.getProperty("os.name").startsWith("Windows") && path.indexOf('/') >= 0) { 042 return path.replace('/', '\\'); 043 } 044 return path; 045 } 046 047 private static synchronized File getDefaultTempDir() { 048 if (defaultTempDir != null 049 && defaultTempDir.exists()) { 050 return defaultTempDir; 051 } 052 053 String s = null; 054 try { 055 s = System.getProperty(FileUtil.class.getName() + ".TempDirectory"); 056 } catch (SecurityException e) { 057 //Ignorable, we'll use the default 058 } 059 if (s == null) { 060 int x = (int)(Math.random() * 1000000); 061 s = System.getProperty("java.io.tmpdir"); 062 File checkExists = new File(s); 063 if (!checkExists.exists()) { 064 throw new RuntimeException("The directory " 065 + checkExists.getAbsolutePath() 066 + " does not exist, please set java.io.tempdir" 067 + " to an existing directory"); 068 } 069 File f = new File(s, "camel-tmp-" + x); 070 while (!f.mkdir()) { 071 x = (int)(Math.random() * 1000000); 072 f = new File(s, "camel-tmp-" + x); 073 } 074 defaultTempDir = f; 075 Thread hook = new Thread() { 076 @Override 077 public void run() { 078 removeDir(defaultTempDir); 079 } 080 }; 081 Runtime.getRuntime().addShutdownHook(hook); 082 } else { 083 //assume someone outside of us will manage the directory 084 File f = new File(s); 085 f.mkdirs(); 086 defaultTempDir = f; 087 } 088 return defaultTempDir; 089 } 090 091 public static void mkDir(File dir) { 092 if (dir == null) { 093 throw new RuntimeException("dir attribute is required"); 094 } 095 096 if (dir.isFile()) { 097 throw new RuntimeException("Unable to create directory as a file " 098 + "already exists with that name: " + dir.getAbsolutePath()); 099 } 100 101 if (!dir.exists()) { 102 boolean result = doMkDirs(dir); 103 if (!result) { 104 String msg = "Directory " + dir.getAbsolutePath() 105 + " creation was not successful for an unknown reason"; 106 throw new RuntimeException(msg); 107 } 108 } 109 } 110 111 /** 112 * Attempt to fix possible race condition when creating directories on 113 * WinXP, also Windows2000. If the mkdirs does not work, wait a little and 114 * try again. 115 */ 116 private static boolean doMkDirs(File f) { 117 if (!f.mkdirs()) { 118 try { 119 Thread.sleep(RETRY_SLEEP_MILLIS); 120 return f.mkdirs(); 121 } catch (InterruptedException ex) { 122 return f.mkdirs(); 123 } 124 } 125 return true; 126 } 127 128 public static void removeDir(File d) { 129 String[] list = d.list(); 130 if (list == null) { 131 list = new String[0]; 132 } 133 for (int i = 0; i < list.length; i++) { 134 String s = list[i]; 135 File f = new File(d, s); 136 if (f.isDirectory()) { 137 removeDir(f); 138 } else { 139 delete(f); 140 } 141 } 142 delete(d); 143 } 144 145 public static void delete(File f) { 146 if (!f.delete()) { 147 if (isWindows()) { 148 System.gc(); 149 } 150 try { 151 Thread.sleep(RETRY_SLEEP_MILLIS); 152 } catch (InterruptedException ex) { 153 // Ignore Exception 154 } 155 if (!f.delete()) { 156 f.deleteOnExit(); 157 } 158 } 159 } 160 161 private static boolean isWindows() { 162 String osName = System.getProperty("os.name").toLowerCase(Locale.US); 163 return osName.indexOf("windows") > -1; 164 } 165 166 public static File createTempFile(String prefix, String suffix) throws IOException { 167 return createTempFile(prefix, suffix, null, false); 168 } 169 170 public static File createTempFile(String prefix, String suffix, File parentDir, 171 boolean deleteOnExit) throws IOException { 172 File result = null; 173 File parent = (parentDir == null) 174 ? getDefaultTempDir() 175 : parentDir; 176 177 if (suffix == null) { 178 suffix = ".tmp"; 179 } 180 if (prefix == null) { 181 prefix = "camel"; 182 } else if (prefix.length() < 3) { 183 prefix = prefix + "camel"; 184 } 185 result = File.createTempFile(prefix, suffix, parent); 186 187 //if parentDir is null, we're in our default dir 188 //which will get completely wiped on exit from our exit 189 //hook. No need to set deleteOnExit() which leaks memory. 190 if (deleteOnExit && parentDir != null) { 191 result.deleteOnExit(); 192 } 193 return result; 194 } 195 196 /** 197 * Strip any leading separators 198 */ 199 public static String stripLeadingSeparator(String name) { 200 if (name == null) { 201 return null; 202 } 203 while (name.startsWith("/") || name.startsWith(File.separator)) { 204 name = name.substring(1); 205 } 206 return name; 207 } 208 209 /** 210 * Strip any trailing separators 211 */ 212 public static String stripTrailingSeparator(String name) { 213 if (name == null) { 214 return null; 215 } 216 while (name.endsWith("/") || name.endsWith(File.separator)) { 217 name = name.substring(0, name.length() - 1); 218 } 219 return name; 220 } 221 222 /** 223 * Strips any leading paths 224 */ 225 public static String stripPath(String name) { 226 if (name == null) { 227 return null; 228 } 229 int pos = name.lastIndexOf('/'); 230 if (pos == -1) { 231 pos = name.lastIndexOf(File.separator); 232 } 233 if (pos != -1) { 234 return name.substring(pos + 1); 235 } 236 return name; 237 } 238 239 /** 240 * Returns only the leading path (returns <tt>null</tt> if no path) 241 */ 242 public static String onlyPath(String name) { 243 if (name == null) { 244 return null; 245 } 246 int pos = name.lastIndexOf('/'); 247 if (pos == -1) { 248 pos = name.lastIndexOf(File.separator); 249 } 250 if (pos != -1) { 251 return name.substring(0, pos); 252 } 253 // no path 254 return null; 255 } 256 257 /** 258 * Compacts a path by stacking it and reducing <tt>..</tt> 259 */ 260 public static String compactPath(String path) { 261 // only normalize path if it contains .. as we want to avoid: path/../sub/../sub2 as this can leads to trouble 262 if (path.indexOf("..") == -1) { 263 return path; 264 } 265 266 Stack<String> stack = new Stack<String>(); 267 String[] parts = path.split(File.separator); 268 for (String part : parts) { 269 if (part.equals("..") && !stack.isEmpty()) { 270 // only pop if there is a previous path 271 stack.pop(); 272 } else { 273 stack.push(part); 274 } 275 } 276 277 // build path based on stack 278 StringBuilder sb = new StringBuilder(); 279 for (Iterator it = stack.iterator(); it.hasNext();) { 280 sb.append(it.next()); 281 if (it.hasNext()) { 282 sb.append(File.separator); 283 } 284 } 285 286 return sb.toString(); 287 } 288 289 }