KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > storage > gammaStore > FileStorageFactory


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.
5
//
6
// $Id: FileStorageFactory.java,v 1.3 2004/03/21 21:05:51 leomekenkamp Exp $
7

8 package org.ozoneDB.core.storage.gammaStore;
9
10 import java.io.File JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.LinkedList JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Properties JavaDoc;
16 import java.util.Random JavaDoc;
17 import java.util.logging.Level JavaDoc;
18 import java.util.logging.Logger JavaDoc;
19 import org.ozoneDB.core.ConfigurationException;
20 import org.ozoneDB.core.storage.PropertyConfigurable;
21 import org.ozoneDB.core.storage.PropertyInfo;
22
23 /**
24  * Abstract base class for storage factories that use files.
25  *
26  * @author <a HREF="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a>
27  * @version $Id: FileStorageFactory.java,v 1.3 2004/03/21 21:05:51 leomekenkamp Exp $
28  */

29 public abstract class FileStorageFactory implements StorageFactory, PropertyConfigurable {
30     
31     private static Logger JavaDoc log = Logger.getLogger(FileStorageFactory.class.getName());
32     
33     public static final PropertyInfo DIRECTORY = new PropertyInfo(
34         ".directory",
35         "string (path)",
36         null,
37         "directory, either relative to the database directory or an absolute path",
38         new String JavaDoc[] {
39             "/var/ozone/index (*nix absolute path)",
40             "c:\\ozoneFiles\\index (windows absolute path)",
41             "index (*nix or windows relative path in database dir)",
42             "./index (*nix relative path in database dir)",
43             ".\\index (windows relative path in database dir)",
44         }
45     );
46
47     private static final String JavaDoc SUBDIRECTORYDEPTH_KEY = ".subdirectoryDepth";
48     private static final String JavaDoc SUBDIRECTORYCOUNT_KEY = ".subdirectoryCount";
49     public static final PropertyInfo SUBDIRECTORYDEPTH = new PropertyInfo(
50         SUBDIRECTORYDEPTH_KEY,
51         "integer (>=0)",
52         "1",
53         "depth of subdirectories to use, to prevent too much files in the " +
54         "directory specified by '.directory' (see: " + SUBDIRECTORYCOUNT_KEY + ")",
55         new String JavaDoc[] {
56             "/var/ozone/index (*nix absolute path)",
57             "c:\\ozoneFiles\\index (windows absolute path)",
58             "index (*nix or windows relative path in database dir)",
59             "./index (*nix relative path in database dir)",
60             ".\\index (windows relative path in database dir)",
61         }
62     );
63
64     public static final PropertyInfo SUBDIRECTORYCOUNT = new PropertyInfo(
65         SUBDIRECTORYCOUNT_KEY,
66         "integer (>=2)",
67         "50",
68         "number of subdirectories to use when " + SUBDIRECTORYDEPTH_KEY +
69         " is greater than 0",
70         new String JavaDoc[] {
71             "/var/ozone/index (*nix absolute path)",
72             "c:\\ozoneFiles\\index (windows absolute path)",
73             "index (*nix or windows relative path in database dir)",
74             "./index (*nix relative path in database dir)",
75             ".\\index (windows relative path in database dir)",
76         }
77     );
78
79     /**
80      * <p>Used to name directories. We could take any value from 2 to
81      * <code>Character.MAX_RADIX</code> (36) here, but we settle for 16 because
82      * it looks nice and nerdy. 36 would look less nice because that could
83      * lead to directories with very nasty words in them when SUBDIRECTORYCOUNT
84      * is large enough.
85      */

86     private static final int NAMECONVERTRADIX = 16;
87
88     private File JavaDoc directory;
89     
90     private String JavaDoc prefix;
91     
92     private int subdirectoryDepth;
93
94     private int subdirectoryCount;
95     
96     /**
97      * As prescribed by the <code>PropertyConfigurable</code> interface.
98      */

99     protected FileStorageFactory(Properties JavaDoc properties, String JavaDoc prefix) {
100         setPrefix(prefix);
101         String JavaDoc property = getPrefix() + DIRECTORY.getKey();
102         String JavaDoc dirName = properties.getProperty(property);
103         if (dirName == null) {
104             String JavaDoc msg = "could not find property: '" + property + "'";
105             if (log.isLoggable(Level.SEVERE)) log.severe(msg + "\ncould find: " + properties.entrySet());
106             
107             throw new ConfigurationException(msg);
108         }
109         File JavaDoc directory = new File JavaDoc(dirName);
110         if (!directory.isAbsolute()) {
111             File JavaDoc databaseRoot = new File JavaDoc(properties.getProperty(GammaStore.DIRECTORY.getKey()));
112             directory = new File JavaDoc(databaseRoot, dirName);
113         }
114         if (!directory.isDirectory() && !directory.mkdir()) {
115             String JavaDoc msg = "could not find nor create directory: '" + dirName + "'";
116             if (log.isLoggable(Level.SEVERE)) log.severe(msg);
117             throw new ConfigurationException(msg);
118         } else {
119             if (log.isLoggable(Level.CONFIG)) log.config(getPrefix() + " using directory " + directory);
120         }
121         setDirectory(directory);
122         
123         // find out the current directory depth by counting the number of dirs
124
// we have to go to find the first file
125
subdirectoryDepth = findDepth(getDirectory(), 0);
126         log.config("current directoryDepth: " + subdirectoryDepth);
127
128         int newDepth = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYDEPTH.getKey(), SUBDIRECTORYDEPTH.getDefaultValue()));
129         log.config("new directoryDepth: " + newDepth);
130         try {
131             setSubdirectoryDepth(newDepth);
132         } catch (IOException JavaDoc e) {
133             ConfigurationException ee = new ConfigurationException("could not change directory depth to " + newDepth, e);
134             log.severe(ee.getMessage());
135             throw ee;
136         }
137         int newCount = Integer.parseInt(properties.getProperty(getPrefix() + SUBDIRECTORYCOUNT.getKey(), SUBDIRECTORYCOUNT.getDefaultValue()));
138         setSubdirectoryCount(newCount);
139     }
140     
141     private int findDepth(File JavaDoc directory, int startDepth) {
142         File JavaDoc[] files = directory.listFiles();
143         for (int i = 0; i < files.length; i++) {
144             if (files[i].isDirectory()) {
145                 int result = findDepth(files[i], startDepth + 1);
146                 if (result > startDepth) {
147                     return result;
148                 }
149             }
150         }
151         for (int i = 0; i < files.length; i++) {
152             if (files[i].isFile()) {
153                 return startDepth;
154             }
155         }
156         return 0;
157     }
158     
159     public void delete(String JavaDoc name) throws IOException JavaDoc {
160         File JavaDoc file = nameToFile(name);
161         if (file.exists() && !file.delete()) {
162             String JavaDoc msg = "could not delete file '" + file + "'";
163             if (log.isLoggable(Level.SEVERE)) log.severe(msg);
164             throw new IOException JavaDoc(msg);
165         }
166     }
167     
168     public void deleteAll() throws IOException JavaDoc {
169         deleteDirectory(getDirectory());
170     }
171     
172     /**
173      * deletes all files and subdirectories in the specified directory, but
174      * does _not_ delete the specified directory
175      */

176     private void deleteDirectory(File JavaDoc directory) throws IOException JavaDoc {
177         File JavaDoc[] files = directory.listFiles();
178         for (int i = 0; i < files.length; i++) {
179             if (files[i].isDirectory()) {
180                 deleteDirectory(files[i]);
181             }
182             if (!files[i].delete()) {
183                 String JavaDoc msg = "could not delete '" + files[i] + "'";
184                 if (log.isLoggable(Level.SEVERE)) log.severe(msg);
185                 throw new IOException JavaDoc(msg);
186             }
187         }
188     }
189  
190     /**
191      * <p>Sets the depth of subdirectories to use. You must make sure that no
192      * reading or writing is taking place in the directory specified by
193      * <code>getDirectory()</code>, either by this class, or outside this class
194      * (for instance with 'cat' or 'type' in a shell / cmd window)</p>.
195      * <p>The whole directory structure is changed when this method is called,
196      * so it may take some time to complete.</p>
197      */

198     private void setSubdirectoryDepth(int depth) throws IOException JavaDoc {
199         if (depth != subdirectoryDepth) {
200             // needs to be debugged or removed altogether
201
// moveFiles(getDirectory(), depth, depth);
202
subdirectoryDepth = depth;
203         }
204     }
205     
206     // DOES NOT WORK!
207
private void moveFiles(File JavaDoc directory, int relDepth, int targetDepth, int targetCount) throws IOException JavaDoc {
208         File JavaDoc[] files = directory.listFiles();
209         if (relDepth == 0) {
210             for (int i = 0; i < files.length; i++) {
211                 File JavaDoc dest = nameToFile(files[i].getName(), targetDepth, targetCount);
212                 ensureParentsExist(dest);
213                 files[i].renameTo(dest);
214             }
215             recursiveDeleteIfEmpty(directory);
216         } else {
217             for (int i = 0; i < files.length; i++) {
218                 if (files[i].isDirectory()) {
219                     moveFiles(files[i], relDepth - 1, targetDepth, targetCount);
220                 }
221             }
222         }
223     }
224     
225     private void recursiveDeleteIfEmpty(File JavaDoc directory) throws IOException JavaDoc {
226         if (directory.isDirectory() && directory.list().length == 0) {
227             if (!directory.delete()) {
228                 throw new IOException JavaDoc("could not delete directory " + directory);
229             }
230             recursiveDeleteIfEmpty(directory.getParentFile());
231         }
232     }
233     
234     private int getSubdirectoryDepth() {
235         return subdirectoryDepth;
236     }
237     
238     public String JavaDoc getPrefix() {
239         return prefix;
240     }
241     
242     /**
243      * Returns the <code>File</code> that corresponds to the given name and
244      * depth.
245      */

246     protected File JavaDoc nameToFile(String JavaDoc name, int depth, int count) {
247         StringBuffer JavaDoc subPath = new StringBuffer JavaDoc();
248         
249         long code = 1;
250         // together with the randomizer, this gives a nice even spread of files
251
// in subdirectories
252
for (int i = 0; i < name.length(); i++) {
253             code = 1 + (code * name.charAt(i)) + (name.charAt(i) * i);
254         }
255         Random JavaDoc random = new Random JavaDoc();
256         for (int i = 0; i < depth; i++) {
257             // all algorithms are fixed across all implementations of the java
258
// specs, so 'random' will generate the same number in every jvm
259
random.setSeed(code * (i + 1));
260             int dirName = Math.abs(random.nextInt() % count);
261             subPath.append(Integer.toString(dirName, NAMECONVERTRADIX));
262             subPath.append(File.separatorChar);
263         }
264         subPath.append(name);
265         File JavaDoc result = new File JavaDoc(getDirectory(), subPath.toString());
266         return result;
267     }
268     
269     protected File JavaDoc nameToFile(String JavaDoc name) {
270         return nameToFile(name, getSubdirectoryDepth(), getSubdirectoryCount());
271     }
272     
273     protected void ensureParentsExist(File JavaDoc file) throws IOException JavaDoc {
274         File JavaDoc parent = file.getParentFile();
275         if (!parent.exists() && !parent.mkdirs()) {
276             throw new IOException JavaDoc("could not create directory " + parent);
277         }
278     }
279         
280     // private so it can be inlined
281
private void setPrefix(String JavaDoc prefix) {
282         this.prefix = prefix;
283     }
284     
285     protected File JavaDoc getDirectory() {
286         return directory;
287     }
288     
289     // private so it can be inlined
290
private void setDirectory(File JavaDoc directory) {
291         this.directory = directory;
292     }
293     
294     /**
295      * Implementing classes should override this method, call super and add
296      * their own specific properties.
297      */

298     public Collection JavaDoc getPropertyInfos() {
299         Collection JavaDoc result = new LinkedList JavaDoc();
300         result.add(DIRECTORY);
301         result.add(SUBDIRECTORYDEPTH);
302         result.add(SUBDIRECTORYCOUNT);
303         return result;
304     }
305     
306     private int getSubdirectoryCount() {
307         return subdirectoryCount;
308     }
309     
310     private void setSubdirectoryCount(int subdirectoryCount) {
311         this.subdirectoryCount = subdirectoryCount;
312     }
313     
314 }
315
Popular Tags