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 }