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 }