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.BufferedReader;
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileReader;
023    import java.io.IOException;
024    import java.io.InputStream;
025    import java.io.InputStreamReader;
026    import java.util.ArrayList;
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Locale;
030    import java.util.Stack;
031    import java.util.regex.Matcher;
032    import java.util.regex.Pattern;
033    
034    /**
035     * File utilities
036     */
037    public final class FileUtil {
038        
039        private static final int RETRY_SLEEP_MILLIS = 10;
040        private static File defaultTempDir;
041    
042        private FileUtil() {
043        }
044    
045        /**
046         * Normalizes the path to cater for Windows and other platforms
047         */
048        public static String normalizePath(String path) {
049            // special handling for Windows where we need to convert / to \\
050            if (path != null && System.getProperty("os.name").startsWith("Windows") && path.indexOf("/") >= 0) {
051                return path.replace('/', '\\');
052            }
053            return path;
054        }
055        
056        private static synchronized File getDefaultTempDir() {
057            if (defaultTempDir != null
058                && defaultTempDir.exists()) {
059                return defaultTempDir;
060            }
061            
062            String s = null;
063            try {
064                s = System.getProperty(FileUtil.class.getName() + ".TempDirectory");
065            } catch (SecurityException e) {
066                //Ignorable, we'll use the default
067            }
068            if (s == null) {
069                int x = (int)(Math.random() * 1000000);
070                s = System.getProperty("java.io.tmpdir");
071                File checkExists = new File(s);
072                if (!checkExists.exists()) {
073                    throw new RuntimeException("The directory " 
074                                           + checkExists.getAbsolutePath() 
075                                           + " does not exist, please set java.io.tempdir"
076                                           + " to an existing directory");
077                }
078                File f = new File(s, "camel-tmp-" + x);
079                while (!f.mkdir()) {
080                    x = (int)(Math.random() * 1000000);
081                    f = new File(s, "camel-tmp-" + x);
082                }
083                defaultTempDir = f;
084                Thread hook = new Thread() {
085                    @Override
086                    public void run() {
087                        removeDir(defaultTempDir);
088                    }
089                };
090                Runtime.getRuntime().addShutdownHook(hook);            
091            } else {
092                //assume someone outside of us will manage the directory
093                File f = new File(s);
094                f.mkdirs();
095                defaultTempDir = f;
096            }
097            return defaultTempDir;
098        }
099    
100        public static void mkDir(File dir) {
101            if (dir == null) {
102                throw new RuntimeException("dir attribute is required");
103            }
104    
105            if (dir.isFile()) {
106                throw new RuntimeException("Unable to create directory as a file "
107                                        + "already exists with that name: " + dir.getAbsolutePath());
108            }
109    
110            if (!dir.exists()) {
111                boolean result = doMkDirs(dir);
112                if (!result) {
113                    String msg = "Directory " + dir.getAbsolutePath()
114                                 + " creation was not successful for an unknown reason";
115                    throw new RuntimeException(msg);
116                }
117            }
118        }
119    
120        /**
121         * Attempt to fix possible race condition when creating directories on
122         * WinXP, also Windows2000. If the mkdirs does not work, wait a little and
123         * try again.
124         */
125        private static boolean doMkDirs(File f) {
126            if (!f.mkdirs()) {
127                try {
128                    Thread.sleep(RETRY_SLEEP_MILLIS);
129                    return f.mkdirs();
130                } catch (InterruptedException ex) {
131                    return f.mkdirs();
132                }
133            }
134            return true;
135        }
136    
137        public static void removeDir(File d) {
138            String[] list = d.list();
139            if (list == null) {
140                list = new String[0];
141            }
142            for (int i = 0; i < list.length; i++) {
143                String s = list[i];
144                File f = new File(d, s);
145                if (f.isDirectory()) {
146                    removeDir(f);
147                } else {
148                    delete(f);
149                }
150            }
151            delete(d);
152        }
153    
154        public static void delete(File f) {
155            if (!f.delete()) {
156                if (isWindows()) {
157                    System.gc();
158                }
159                try {
160                    Thread.sleep(RETRY_SLEEP_MILLIS);
161                } catch (InterruptedException ex) {
162                    // Ignore Exception
163                }
164                if (!f.delete()) {
165                    f.deleteOnExit();
166                }
167            }
168        }
169    
170        private static boolean isWindows() {
171            String osName = System.getProperty("os.name").toLowerCase(Locale.US);
172            return osName.indexOf("windows") > -1;
173        }
174    
175        public static File createTempFile(String prefix, String suffix) throws IOException {
176            return createTempFile(prefix, suffix, null, false);
177        }
178        
179        public static File createTempFile(String prefix, String suffix, File parentDir,
180                                   boolean deleteOnExit) throws IOException {
181            File result = null;
182            File parent = (parentDir == null)
183                ? getDefaultTempDir()
184                : parentDir;
185                
186            if (suffix == null) {
187                suffix = ".tmp";
188            }
189            if (prefix == null) {
190                prefix = "camel";
191            } else if (prefix.length() < 3) {
192                prefix = prefix + "camel";
193            }
194            result = File.createTempFile(prefix, suffix, parent);
195    
196            //if parentDir is null, we're in our default dir
197            //which will get completely wiped on exit from our exit
198            //hook.  No need to set deleteOnExit() which leaks memory.
199            if (deleteOnExit && parentDir != null) {
200                result.deleteOnExit();
201            }
202            return result;
203        }
204        
205        public static String getStringFromFile(File location) {
206            InputStream is = null;
207            String result = null;
208    
209            try {
210                is = new FileInputStream(location);
211                result = normalizeCRLF(is);
212            } catch (Exception e) {
213                e.printStackTrace();
214            } finally {
215                if (is != null) {
216                    try {
217                        is.close();
218                    } catch (Exception e) {
219                        //do nothing
220                    }
221                }
222            }
223    
224            return result;
225        }
226    
227        public static String normalizeCRLF(InputStream instream) {
228            BufferedReader in = new BufferedReader(new InputStreamReader(instream));
229            StringBuffer result = new StringBuffer();
230            String line = null;
231    
232            try {
233                line = in.readLine();
234                while (line != null) {
235                    String[] tok = line.split("\\s");
236    
237                    for (int x = 0; x < tok.length; x++) {
238                        String token = tok[x];
239                        result.append("  " + token);
240                    }
241                    line = in.readLine();
242                }
243            } catch (Exception ex) {
244                ex.printStackTrace();
245            }
246    
247            String rtn = result.toString();
248    
249            rtn = ignoreTokens(rtn, "<!--", "-->");
250            rtn = ignoreTokens(rtn, "/*", "*/");
251            return rtn;
252        }
253        
254        private static String ignoreTokens(final String contents, 
255                                           final String startToken, final String endToken) {
256            String rtn = contents;
257            int headerIndexStart = rtn.indexOf(startToken);
258            int headerIndexEnd = rtn.indexOf(endToken);
259            if (headerIndexStart != -1 && headerIndexEnd != -1 && headerIndexStart < headerIndexEnd) {
260                rtn = rtn.substring(0, headerIndexStart - 1)
261                    + rtn.substring(headerIndexEnd + endToken.length() + 1);
262            }
263            return rtn;
264        }
265    
266        public static List<File> getFiles(File dir, final String pattern) {
267            return getFiles(dir, pattern, null);
268        }
269        public static List<File> getFilesRecurse(File dir, final String pattern) {
270            return getFilesRecurse(dir, pattern, null);
271        }
272    
273        public static List<File> getFiles(File dir, final String pattern, File exclude) {
274            return getFilesRecurse(dir, Pattern.compile(pattern), exclude, false, new ArrayList<File>());
275        }
276        public static List<File> getFilesRecurse(File dir, final String pattern, File exclude) {
277            return getFilesRecurse(dir, Pattern.compile(pattern), exclude, true, new ArrayList<File>());    
278        }
279        private static List<File> getFilesRecurse(File dir, 
280                                                  Pattern pattern,
281                                                  File exclude, boolean rec,
282                                                  List<File> fileList) {
283            for (File file : dir.listFiles()) {
284                if (file.equals(exclude)) {
285                    continue;
286                }
287                if (file.isDirectory() && rec) {
288                    getFilesRecurse(file, pattern, exclude, rec, fileList);
289                } else {
290                    Matcher m = pattern.matcher(file.getName());
291                    if (m.matches()) {
292                        fileList.add(file);                                
293                    }
294                }
295            }
296            return fileList;
297        }
298    
299        public static List<String> readLines(File file) throws Exception {
300            if (!file.exists()) {
301                return new ArrayList<String>();
302            }
303            BufferedReader reader = new BufferedReader(new FileReader(file));
304            List<String> results = new ArrayList<String>();
305            String line = reader.readLine();
306            while (line != null) {
307                results.add(line);
308                line = reader.readLine();
309            }
310            return results;
311        }
312    
313        /**
314         * Strip any leading separators
315         */
316        public static String stripLeadingSeparator(String name) {
317            if (name == null) {
318                return null;
319            }
320            while (name.startsWith("/") || name.startsWith(File.separator)) {
321                name = name.substring(1);
322            }
323            return name;
324        }
325    
326        /**
327         * Strip any trailing separators
328         */
329        public static String stripTrailingSeparator(String name) {
330            if (name == null) {
331                return null;
332            }
333            while (name.endsWith("/") || name.endsWith(File.separator)) {
334                name = name.substring(0, name.length() - 1);
335            }
336            return name;
337        }
338    
339        /**
340         * Strips any leading paths
341         */
342        public static String stripPath(String name) {
343            if (name == null) {
344                return null;
345            }
346            int pos = name.lastIndexOf("/");
347            if (pos == -1) {
348                pos = name.lastIndexOf(File.separator);
349            }
350            if (pos != -1) {
351                return name.substring(pos + 1);
352            }
353            return name;
354        }
355    
356        /**
357         * Returns only the leading path (returns <tt>null</tt> if no path)
358         */
359        public static String onlyPath(String name) {
360            if (name == null) {
361                return null;
362            }
363            int pos = name.lastIndexOf("/");
364            if (pos == -1) {
365                pos = name.lastIndexOf(File.separator);
366            }
367            if (pos != -1) {
368                return name.substring(0, pos);
369            }
370            // no path
371            return null;
372        }
373    
374        /**
375         * Compacts a path by stacking it and reducing <tt>..</tt>
376         */
377        public static String compactPath(String path) {
378            // only normalize path if it contains .. as we want to avoid: path/../sub/../sub2 as this can leads to trouble
379            if (path.indexOf("..") == -1) {
380                return path;
381            }
382    
383            Stack<String> stack = new Stack<String>();
384            String[] parts = path.split(File.separator);
385            for (String part : parts) {
386                if (part.equals("..") && !stack.isEmpty()) {
387                    // only pop if there is a previous path
388                    stack.pop();
389                } else {
390                    stack.push(part);
391                }
392            }
393    
394            // build path based on stack
395            StringBuilder sb = new StringBuilder();
396            for (Iterator it = stack.iterator(); it.hasNext();) {
397                sb.append(it.next());
398                if (it.hasNext()) {
399                    sb.append(File.separator);
400                }
401            }
402    
403            return sb.toString();
404        }
405    
406    }