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.activemq.util;
018    
019    import java.io.File;
020    import java.io.FileInputStream;
021    import java.io.FileNotFoundException;
022    import java.io.FileOutputStream;
023    import java.io.FilenameFilter;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.OutputStream;
027    import java.util.ArrayList;
028    import java.util.List;
029    
030    /**
031     * 
032     */
033    public final class IOHelper {
034        protected static final int MAX_DIR_NAME_LENGTH;
035        protected static final int MAX_FILE_NAME_LENGTH;
036        private static final int DEFAULT_BUFFER_SIZE = 4096;
037        private IOHelper() {
038        }
039    
040        public static String getDefaultDataDirectory() {
041            return getDefaultDirectoryPrefix() + "activemq-data";
042        }
043    
044        public static String getDefaultStoreDirectory() {
045            return getDefaultDirectoryPrefix() + "amqstore";
046        }
047    
048        /**
049         * Allows a system property to be used to overload the default data
050         * directory which can be useful for forcing the test cases to use a target/
051         * prefix
052         */
053        public static String getDefaultDirectoryPrefix() {
054            try {
055                return System.getProperty("org.apache.activemq.default.directory.prefix", "");
056            } catch (Exception e) {
057                return "";
058            }
059        }
060    
061        /**
062         * Converts any string into a string that is safe to use as a file name.
063         * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
064         *
065         * @param name
066         * @return
067         */
068        public static String toFileSystemDirectorySafeName(String name) {
069            return toFileSystemSafeName(name, true, MAX_DIR_NAME_LENGTH);
070        }
071        
072        public static String toFileSystemSafeName(String name) {
073            return toFileSystemSafeName(name, false, MAX_FILE_NAME_LENGTH);
074        }
075        
076        /**
077         * Converts any string into a string that is safe to use as a file name.
078         * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
079         *
080         * @param name
081         * @param dirSeparators 
082         * @param maxFileLength 
083         * @return
084         */
085        public static String toFileSystemSafeName(String name,boolean dirSeparators,int maxFileLength) {
086            int size = name.length();
087            StringBuffer rc = new StringBuffer(size * 2);
088            for (int i = 0; i < size; i++) {
089                char c = name.charAt(i);
090                boolean valid = c >= 'a' && c <= 'z';
091                valid = valid || (c >= 'A' && c <= 'Z');
092                valid = valid || (c >= '0' && c <= '9');
093                valid = valid || (c == '_') || (c == '-') || (c == '.') || (c=='#')
094                        ||(dirSeparators && ( (c == '/') || (c == '\\')));
095    
096                if (valid) {
097                    rc.append(c);
098                } else {
099                    // Encode the character using hex notation
100                    rc.append('#');
101                    rc.append(HexSupport.toHexFromInt(c, true));
102                }
103            }
104            String result = rc.toString();
105            if (result.length() > maxFileLength) {
106                result = result.substring(result.length()-maxFileLength,result.length());
107            }
108            return result;
109        }
110        
111        public static boolean deleteFile(File fileToDelete) {
112            if (fileToDelete == null || !fileToDelete.exists()) {
113                return true;
114            }
115            boolean result = deleteChildren(fileToDelete);
116            result &= fileToDelete.delete();
117            return result;
118        }
119        
120        public static boolean deleteChildren(File parent) {
121            if (parent == null || !parent.exists()) {
122                return false;
123            }
124            boolean result = true;
125            if (parent.isDirectory()) {
126                File[] files = parent.listFiles();
127                if (files == null) {
128                    result = false;
129                } else {
130                    for (int i = 0; i < files.length; i++) {
131                        File file = files[i];
132                        if (file.getName().equals(".")
133                                || file.getName().equals("..")) {
134                            continue;
135                        }
136                        if (file.isDirectory()) {
137                            result &= deleteFile(file);
138                        } else {
139                            result &= file.delete();
140                        }
141                    }
142                }
143            }
144           
145            return result;
146        }
147        
148        
149        public static void moveFile(File src, File targetDirectory) throws IOException {
150            if (!src.renameTo(new File(targetDirectory, src.getName()))) {
151                throw new IOException("Failed to move " + src + " to " + targetDirectory);
152            }
153        }
154        
155        public static void copyFile(File src, File dest) throws IOException {
156            copyFile(src,dest,null);
157        }
158        
159        public static void copyFile(File src, File dest, FilenameFilter filter) throws IOException {
160            if (src.getCanonicalPath().equals(dest.getCanonicalPath()) == false) {
161                if (src.isDirectory()) {
162    
163                    mkdirs(dest);
164                    List<File> list = getFiles(src, filter);
165                    for (File f : list) {
166                        if (f.isFile()) {
167                            File target = new File(getCopyParent(src, dest, f), f.getName());
168                            copySingleFile(f, target);
169                        }
170                    }
171    
172                } else if (dest.isDirectory()) {
173                    mkdirs(dest);
174                    File target = new File(dest, src.getName());
175                    copySingleFile(src, target);
176                } else {
177                    copySingleFile(src, dest);
178                }
179            }
180        }
181        
182        static File getCopyParent(File from, File to, File src) {
183            File result = null;
184            File parent = src.getParentFile();
185            String fromPath = from.getAbsolutePath();
186            if (parent.getAbsolutePath().equals(fromPath)) {
187                //one level down
188                result = to;
189            }else {
190                String parentPath = parent.getAbsolutePath();
191                String path = parentPath.substring(fromPath.length());
192                result = new File(to.getAbsolutePath()+File.separator+path);
193            }
194            return result;
195        }
196        
197        static List<File> getFiles(File dir,FilenameFilter filter){
198            List<File> result = new ArrayList<File>();
199            getFiles(dir,result,filter);
200            return result;
201        }
202        
203        static void getFiles(File dir,List<File> list,FilenameFilter filter) {
204            if (!list.contains(dir)) {
205                list.add(dir);
206                String[] fileNames=dir.list(filter);
207                for (int i =0; i < fileNames.length;i++) {
208                    File f = new File(dir,fileNames[i]);
209                    if (f.isFile()) {
210                        list.add(f);
211                    }else {
212                        getFiles(dir,list,filter);
213                    }
214                }
215            }
216        }
217        
218        
219        public static void copySingleFile(File src, File dest) throws IOException {
220            FileInputStream fileSrc = new FileInputStream(src);
221            FileOutputStream fileDest = new FileOutputStream(dest);
222            copyInputStream(fileSrc, fileDest);
223        }
224        
225        public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
226            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
227            int len = in.read(buffer);
228            while (len >= 0) {
229                out.write(buffer, 0, len);
230                len = in.read(buffer);
231            }
232            in.close();
233            out.close();
234        }
235        
236        static {
237            MAX_DIR_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumDirNameLength","200")).intValue();  
238            MAX_FILE_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumFileNameLength","64")).intValue();             
239        }
240    
241        
242        public static void mkdirs(File dir) throws IOException {
243            if (dir.exists()) {
244                if (!dir.isDirectory()) {
245                    throw new IOException("Failed to create directory '" + dir +"', regular file already existed with that name");
246                }
247                
248            } else {
249                if (!dir.mkdirs()) {
250                    throw new IOException("Failed to create directory '" + dir+"'");
251                }
252            }
253        }
254    }