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