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 */
017package org.apache.kahadb.util;
018
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileNotFoundException;
022import java.io.FileOutputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.OutputStream;
026
027/**
028 * 
029 */
030public final class IOHelper {
031    protected static final int MAX_DIR_NAME_LENGTH;
032    protected static final int MAX_FILE_NAME_LENGTH;
033    private static final int DEFAULT_BUFFER_SIZE = 4096;
034    private IOHelper() {
035    }
036
037    public static String getDefaultDataDirectory() {
038        return getDefaultDirectoryPrefix() + "activemq-data";
039    }
040
041    public static String getDefaultStoreDirectory() {
042        return getDefaultDirectoryPrefix() + "amqstore";
043    }
044
045    /**
046     * Allows a system property to be used to overload the default data
047     * directory which can be useful for forcing the test cases to use a target/
048     * prefix
049     */
050    public static String getDefaultDirectoryPrefix() {
051        try {
052            return System.getProperty("org.apache.activemq.default.directory.prefix", "");
053        } catch (Exception e) {
054            return "";
055        }
056    }
057
058    /**
059     * Converts any string into a string that is safe to use as a file name.
060     * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
061     *
062     * @param name
063     * @return
064     */
065    public static String toFileSystemDirectorySafeName(String name) {
066        return toFileSystemSafeName(name, true, MAX_DIR_NAME_LENGTH);
067    }
068    
069    public static String toFileSystemSafeName(String name) {
070        return toFileSystemSafeName(name, false, MAX_FILE_NAME_LENGTH);
071    }
072    
073    /**
074     * Converts any string into a string that is safe to use as a file name.
075     * The result will only include ascii characters and numbers, and the "-","_", and "." characters.
076     *
077     * @param name
078     * @param dirSeparators 
079     * @param maxFileLength 
080     * @return
081     */
082    public static String toFileSystemSafeName(String name,boolean dirSeparators,int maxFileLength) {
083        int size = name.length();
084        StringBuffer rc = new StringBuffer(size * 2);
085        for (int i = 0; i < size; i++) {
086            char c = name.charAt(i);
087            boolean valid = c >= 'a' && c <= 'z';
088            valid = valid || (c >= 'A' && c <= 'Z');
089            valid = valid || (c >= '0' && c <= '9');
090            valid = valid || (c == '_') || (c == '-') || (c == '.') || (c=='#')
091                    ||(dirSeparators && ( (c == '/') || (c == '\\')));
092
093            if (valid) {
094                rc.append(c);
095            } else {
096                // Encode the character using hex notation
097                rc.append('#');
098                rc.append(HexSupport.toHexFromInt(c, true));
099            }
100        }
101        String result = rc.toString();
102        if (result.length() > maxFileLength) {
103            result = result.substring(result.length()-maxFileLength,result.length());
104        }
105        return result;
106    }
107    
108    public static boolean deleteFile(File fileToDelete) {
109        if (fileToDelete == null || !fileToDelete.exists()) {
110            return true;
111        }
112        boolean result = deleteChildren(fileToDelete);
113        result &= fileToDelete.delete();
114        return result;
115    }
116    
117    public static boolean deleteChildren(File parent) {
118        if (parent == null || !parent.exists()) {
119            return false;
120        }
121        boolean result = true;
122        if (parent.isDirectory()) {
123            File[] files = parent.listFiles();
124            if (files == null) {
125                result = false;
126            } else {
127                for (int i = 0; i < files.length; i++) {
128                    File file = files[i];
129                    if (file.getName().equals(".")
130                            || file.getName().equals("..")) {
131                        continue;
132                    }
133                    if (file.isDirectory()) {
134                        result &= deleteFile(file);
135                    } else {
136                        result &= file.delete();
137                    }
138                }
139            }
140        }
141       
142        return result;
143    }
144    
145    
146    public static void moveFile(File src, File targetDirectory) throws IOException {
147        if (!src.renameTo(new File(targetDirectory, src.getName()))) {
148            throw new IOException("Failed to move " + src + " to " + targetDirectory);
149        }
150    }
151    
152    public static void copyFile(File src, File dest) throws IOException {
153        FileInputStream fileSrc = new FileInputStream(src);
154        FileOutputStream fileDest = new FileOutputStream(dest);
155        copyInputStream(fileSrc, fileDest);
156    }
157    
158    public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
159        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
160        int len = in.read(buffer);
161        while (len >= 0) {
162            out.write(buffer, 0, len);
163            len = in.read(buffer);
164        }
165        in.close();
166        out.close();
167    }
168    
169    static {
170        MAX_DIR_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumDirNameLength","200")).intValue();  
171        MAX_FILE_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumFileNameLength","64")).intValue();             
172    }
173
174    
175    public static void mkdirs(File dir) throws IOException {
176        if (dir.exists()) {
177            if (!dir.isDirectory()) {
178                throw new IOException("Failed to create directory '" + dir +"', regular file already existed with that name");
179            }
180            
181        } else {
182            if (!dir.mkdirs()) {
183                throw new IOException("Failed to create directory '" + dir+"'");
184            }
185        }
186    }
187}