]> git.evergreen-ils.org Git - working/Hatch.git/blob - src/org/evergreen_ils/hatch/FileIO.java
LP1825896 Migrate values to new data directory
[working/Hatch.git] / src / org / evergreen_ils / hatch / FileIO.java
1 /* -----------------------------------------------------------------------
2  * Copyright 2014 Equinox Software, Inc.
3  * Bill Erickson <berick@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * -----------------------------------------------------------------------
15  */
16 package org.evergreen_ils.hatch;
17
18 import java.io.*;
19 import java.util.LinkedList;
20 import java.util.Arrays;
21 import java.util.logging.Logger;
22
23 public class FileIO {
24
25     /** All files are read from and written to this directory */
26     String basePath;
27     String originDomain;
28
29     // routine for scrubbing invalid chars from file names / paths
30     // http://stackoverflow.com/questions/1155107/is-there-a-cross-platform-java-method-to-remove-filename-special-chars
31     final static int[] illegalChars = {
32         34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
33         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 
34         58, 42, 63, 92, 47
35     };
36
37     static { Arrays.sort(illegalChars); }
38
39     public static String cleanFileName(String badFileName) {
40         char lastChar = 0;
41         StringBuilder cleanName = new StringBuilder();
42         for (int i = 0; i < badFileName.length(); i++) {
43             int c = (int)badFileName.charAt(i);
44             if (Arrays.binarySearch(illegalChars, c) < 0) {
45                 cleanName.append((char)c);
46                 lastChar = (char) c;
47             } else {
48                 // avoid dupe-ing the placeholder chars, since that
49                 // relays no useful information (apart from the number
50                 // of illegal characters)
51                 // This is usefuf or things like https:// with dupe "/" chars
52                 if (lastChar != '_')
53                     cleanName.append('_');
54                 lastChar = '_';
55             }
56         }
57         return cleanName.toString();
58     }
59     // -------------------------------------------------- 
60
61     // logger
62     static final Logger logger = Logger.getLogger("org.evergreen_ils.hatch");
63
64     /**
65      * Constructs a new FileIO with the provided base path.
66      *
67      * @param directory Directory to use in conjuction with the origin
68      * (see below) as the base path for all file operations.
69      * directory is assumed to be a valid path.
70      * @param origin Origin domain of this request.  
71      */
72     public FileIO(String directory, String origin) {
73         basePath = directory;  
74         originDomain = cleanFileName(origin);
75     }
76
77     /**
78      * Returns the base directory as a File for all file IO actions
79      */
80     protected File baseDir() {
81
82         // basePath directory
83         File dir = new File(basePath);
84         if (!dir.exists()) {
85             if (!dir.mkdir()) {
86                 //logger.info("Unable to create directory: " + dir.getName());
87                 return null;
88             }
89         }
90
91         // basePath + originDomain directory
92         File subDir = new File(basePath, originDomain);
93         if (!subDir.exists()) {
94             if (!subDir.mkdir()) {
95                 //logger.info("Unable to create directory: " + subDir.getName());
96                 return null;
97             }
98         }
99
100         //logger.info("baseDir: " + subDir.getName());
101         return subDir;
102     }
103
104     /**
105      * Locates the requested file by name within our configured base path.
106      *
107      * @param key The relative file name (key)
108      * @return The File object if found.
109      */
110     protected File getFile(String key) {
111         File baseDir = baseDir();
112         if (baseDir == null) return null;
113         key = cleanFileName(key);
114         return new File(baseDir, key);
115     }
116
117     /**
118      * Sets the content of a file.
119      *
120      * @param key The relative file name (key)
121      * @param text The new file content
122      *
123      * @return success or failure
124      */
125     public boolean set(String key, String text) {
126         //logger.info("set => " + key);
127         File file = getFile(key);
128
129         if (text == null) return false;
130
131         try {
132
133             // delete the file if it exists
134             if (!file.exists() && !file.createNewFile()) {
135                 //logger.info(
136                     //"Unable to create file: " + file.getCanonicalPath());
137                 return false;
138             }
139
140             // destructive write (replace existing text)
141             Writer outStream = new BufferedWriter(
142                 new FileWriter(file.getAbsoluteFile()));
143
144             outStream.write(text);
145             outStream.close();
146
147         } catch(IOException e) {
148             //logger.warn("Error calling set() with key " + key);
149             //logger.warn(e);
150             return false;
151         }
152
153         return true;
154     }
155
156     /**
157      * Appends content to a file.
158      *
159      * If the file does not exist, it is first created.
160      *
161      * @param key The relative file name (key)
162      * @param text The content to append to the file
163      * @return success or failure
164      */
165     public boolean append(String key, String text) {
166         //logger.info("append => " + key);
167         File file = getFile(key);
168
169         try {
170
171             // create the file if it doesn's already exist
172             if (!file.exists() && !file.createNewFile()) {
173                 //logger.info(
174                     //"Unable to create file: " + file.getCanonicalPath());
175                 return false;
176             }
177
178             // non-destructive write (append)
179             Writer outStream = new BufferedWriter(
180                 new FileWriter(file.getAbsoluteFile(), true));
181             outStream.write(text);
182             outStream.close();
183
184         } catch(IOException e) {
185             //logger.warn("Error in append() with key " + key);
186             //logger.warn(e);
187             return false;
188         }
189
190         return true;
191     }
192
193     /**
194      * Gets the text contents of a file.
195      *
196      * @param key The relative file name (key)
197      * @return The text content of the file
198      */
199     public String get(String key) {
200         //logger.info("get => " + key);
201         File file = getFile(key);
202         if (!file.exists()) return null;
203
204         String line;
205         StringBuffer buf = new StringBuffer();
206
207         try {
208             BufferedReader reader = new BufferedReader(
209                 new FileReader(file.getAbsoluteFile()));
210
211             while ( (line = reader.readLine()) != null) {
212                 buf.append(line);
213             }
214         } catch (IOException e) {
215             //logger.warn("Error reading key: " + key);
216             //logger.warn(e);
217             return null;
218         }
219
220         return buf.toString();
221     }
222
223     /**
224      * Removes (deletes) a file.
225      *
226      * @param The relative file name (key)
227      * @return success or failure
228      */
229     public boolean remove(String key) {
230         //logger.info("remove => " + key);
231         File file = getFile(key);
232         //try {
233             if (file.exists() && !file.delete()) {
234                 //logger.info(
235                     //"Unable to delete file: " + file.getCanonicalPath());
236                 return false;
237             }
238             return true;
239         //} catch (IOException e) {
240             //logger.warn("Error deleting key: " + key);
241             //logger.warn(e);
242             //return false;
243         //}
244     }
245
246     /**
247      * Returns the full list of stored keys.
248      *
249      * @return Array of relative file names
250      */
251     public String[] keys() {
252         return keys(null);
253     }
254
255     /**
256      * Returns all keys begining with the specified prefix.
257      *
258      * @param prefix The initial substring used to limit the return set 
259      * of keys.  If the prefix is null, all keys are returned.
260      * @return Array of keys
261      */
262     public String[] keys(String prefix) {
263         //logger.info("keys => " + prefix);
264
265         File dir = baseDir();
266         if (dir == null || !dir.exists()) 
267             return new String[0];
268
269         LinkedList<String> nameList = new LinkedList<String>();
270         File[] files = dir.listFiles();
271
272         for (File file : files) {
273             if (file.isFile()) {
274                 String name = file.getName();
275                 if (prefix == null) {
276                     nameList.add(name);
277                 } else {
278                     if (name.startsWith(prefix)) {
279                         nameList.add(name);
280                     }
281                 }
282             }
283         }
284
285         return (String[]) nameList.toArray(new String[0]);
286     }
287
288
289     // Migrate stored values from an old profile directory to a new one.
290     // If the destination path does not exists for the origin,
291     // create the path and copy data from the old profile dir to 
292     // the new profile dir. The source directory is unmodified.
293     public void migrateProfileData(String newDir, String oldDir, String origin) {
294         origin = cleanFileName(origin);
295
296         // basePath directory
297         File baseDir = new File(newDir);
298         if (!baseDir.exists()) {
299             if (!baseDir.mkdir()) {
300                 logger.warning("Unable to create baseDirectory: " + baseDir.getPath());
301             }
302         }
303
304         File originDir = new File(newDir, origin);
305         if (originDir.exists()) {
306             // New dir is already built.  No need to migrate.
307             return;
308         }
309
310         File oldOriginDir = new File(oldDir, origin);
311
312         if (oldOriginDir.exists()) {
313             logger.info("Migrating data from " + 
314                 oldDir + " to " + newDir + " for origin " + origin);
315
316             FileIO oldFiles = new FileIO(oldDir, origin);
317             for (String key: oldFiles.keys()) {
318                 logger.info("Migrating key " + key);
319                 String val = oldFiles.get(key);
320                 this.set(key, val);
321             }
322
323         } else {
324             // create a new directory
325             if (!originDir.mkdir()) {
326                 logger.warning(
327                     "Error creating data directory: " + originDir.getPath());
328             }
329         }
330     }
331 }
332