KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > cache > loader > FileCacheLoader


1 package org.jboss.cache.loader;
2
3 import org.apache.commons.logging.Log;
4 import org.apache.commons.logging.LogFactory;
5 import org.jboss.cache.Fqn;
6 import org.jboss.cache.Modification;
7 import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
8 import org.jboss.util.stream.MarshalledValueInputStream;
9
10 import java.io.File JavaDoc;
11 import java.io.FileInputStream JavaDoc;
12 import java.io.FileOutputStream JavaDoc;
13 import java.io.IOException JavaDoc;
14 import java.io.ObjectOutputStream JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20 import java.util.concurrent.ConcurrentHashMap JavaDoc;
21 import java.util.regex.Matcher JavaDoc;
22 import java.util.regex.Pattern JavaDoc;
23
24 /**
25  * Simple file-based CacheLoader implementation. Nodes are directories, attributes of a node is a file in the directory
26  *
27  * @author Bela Ban
28  * @version $Id: FileCacheLoader.java,v 1.28 2006/12/30 17:50:01 msurtani Exp $
29  */

30 public class FileCacheLoader extends AbstractCacheLoader
31 {
32    File JavaDoc root = null;
33    String JavaDoc rootPath = null;
34    Log log = LogFactory.getLog(getClass());
35
36    private FileCacheLoaderConfig config;
37
38    /**
39     * HashMap<Object,List<Modification>>. List of open transactions. Note that this is purely transient, as
40     * we don't use a log, recovery is not available
41     */

42    Map JavaDoc<Object JavaDoc, List JavaDoc<Modification>> transactions = new ConcurrentHashMap JavaDoc();
43
44    /**
45     * CacheImpl data file.
46     */

47    public static final String JavaDoc DATA = "data.dat";
48
49    /**
50     * CacheImpl directory suffix.
51     */

52    public static final String JavaDoc DIR_SUFFIX = "fdb";
53
54    /**
55     * For full path, check '*' '<' '>' '|' '"' '?' Regex: [\*<>|"?]
56     */

57    public static final Pattern JavaDoc PATH_PATTERN = Pattern.compile("[\\*<>|\"?]");
58
59    /**
60     * For fqn, check '*' '<' '>' '|' '"' '?' and also '\' '/' and ':'
61     */

62    public static final Pattern JavaDoc FQN_PATTERN = Pattern.compile("[\\\\\\/:*<>|\"?]");
63
64    public FileCacheLoader()
65    {
66    }
67
68    public void setConfig(IndividualCacheLoaderConfig base)
69    {
70       if (base instanceof FileCacheLoaderConfig)
71       {
72          this.config = (FileCacheLoaderConfig) base;
73       }
74       else if (base != null)
75       {
76          this.config = new FileCacheLoaderConfig(base);
77       }
78
79       String JavaDoc location = this.config != null ? this.config.getLocation() : null;
80       if (location != null && location.length() > 0)
81       {
82          root = new File JavaDoc(location);
83          rootPath = root.getAbsolutePath() + File.separator;
84       }
85    }
86
87    public IndividualCacheLoaderConfig getConfig()
88    {
89       return config;
90    }
91
92    public void create() throws Exception JavaDoc
93    {
94       if (root == null)
95       {
96          String JavaDoc tmpLocation = System.getProperty("java.io.tmpdir", "C:\\tmp");
97          root = new File JavaDoc(tmpLocation);
98          rootPath = root.getAbsolutePath() + File.separator;
99       }
100       if (!root.exists())
101       {
102          if (log.isTraceEnabled())
103          {
104             log.trace("Creating cache loader location " + root);
105          }
106
107          if (config.isCheckCharacterPortability())
108          {
109             /* Before creating the root, check whether the path is character portable. Anything that comes after is part
110                of the fqn which is inspected later. */

111             isCharacterPortableLocation(root.getAbsolutePath());
112          }
113
114          boolean created = root.mkdirs();
115          if (!created)
116          {
117             throw new IOException JavaDoc("Unable to create cache loader location " + root);
118          }
119       }
120
121       if (!root.isDirectory())
122       {
123          throw new IOException JavaDoc("Cache loader location [" + root + "] is not a directory!");
124       }
125    }
126
127    public void start() throws Exception JavaDoc
128    {
129    }
130
131    public void stop()
132    {
133    }
134
135    public void destroy()
136    {
137    }
138
139    public Set JavaDoc<String JavaDoc> getChildrenNames(Fqn fqn) throws Exception JavaDoc
140    {
141       File JavaDoc parent = getDirectory(fqn, false);
142       if (parent == null) return null;
143       File JavaDoc[] children = parent.listFiles();
144       Set JavaDoc<String JavaDoc> s = new HashSet JavaDoc<String JavaDoc>();
145       for (int i = 0; i < children.length; i++)
146       {
147          File JavaDoc child = children[i];
148          if (child.isDirectory() && child.getName().endsWith(DIR_SUFFIX))
149          {
150             String JavaDoc child_name = child.getName();
151             child_name = child_name.substring(0, child_name.lastIndexOf(DIR_SUFFIX) - 1);
152             s.add(child_name);
153          }
154       }
155       return s.size() == 0 ? null : s;
156    }
157
158    public Map JavaDoc get(Fqn fqn) throws Exception JavaDoc
159    {
160       return loadAttributes(fqn);
161    }
162
163    public boolean exists(Fqn fqn) throws Exception JavaDoc
164    {
165       File JavaDoc f = getDirectory(fqn, false);
166       return f != null;
167    }
168
169    public Object JavaDoc put(Fqn fqn, Object JavaDoc key, Object JavaDoc value) throws Exception JavaDoc
170    {
171       Object JavaDoc retval;
172       Map JavaDoc m = loadAttributes(fqn);
173       if (m == null) m = new HashMap JavaDoc();
174       retval = m.put(key, value);
175       storeAttributes(fqn, m);
176       return retval;
177    }
178
179    public void put(Fqn fqn, Map JavaDoc attributes) throws Exception JavaDoc
180    {
181       put(fqn, attributes, false);
182    }
183
184
185    public void put(Fqn fqn, Map JavaDoc attributes, boolean erase) throws Exception JavaDoc
186    {
187       Map JavaDoc m = erase ? new HashMap JavaDoc() : loadAttributes(fqn);
188       if (m == null) m = new HashMap JavaDoc();
189       if (attributes != null)
190       {
191          m.putAll(attributes);
192       }
193       storeAttributes(fqn, m);
194    }
195
196    void put(Fqn fqn) throws Exception JavaDoc
197    {
198       getDirectory(fqn, true);
199    }
200
201    public Object JavaDoc remove(Fqn fqn, Object JavaDoc key) throws Exception JavaDoc
202    {
203       Object JavaDoc retval;
204       Map JavaDoc m = loadAttributes(fqn);
205       if (m == null) return null;
206       retval = m.remove(key);
207       storeAttributes(fqn, m);
208       return retval;
209    }
210
211    public void remove(Fqn fqn) throws Exception JavaDoc
212    {
213       File JavaDoc dir = getDirectory(fqn, false);
214       if (dir != null)
215       {
216          boolean flag = removeDirectory(dir, true);
217          if (!flag)
218          {
219             log.warn("failed removing " + fqn);
220          }
221       }
222    }
223
224    public void removeData(Fqn fqn) throws Exception JavaDoc
225    {
226       File JavaDoc f = getDirectory(fqn, false);
227       if (f != null)
228       {
229          File JavaDoc data = new File JavaDoc(f, DATA);
230          if (data.exists())
231          {
232             boolean flag = data.delete();
233             if (!flag)
234             {
235                log.warn("failed removing file " + data.getName());
236             }
237          }
238       }
239    }
240
241    public void prepare(Object JavaDoc tx, List JavaDoc<Modification> modifications, boolean one_phase) throws Exception JavaDoc
242    {
243       if (one_phase)
244       {
245          put(modifications);
246       }
247       else
248       {
249          transactions.put(tx, modifications);
250       }
251    }
252
253    public void commit(Object JavaDoc tx) throws Exception JavaDoc
254    {
255       List JavaDoc modifications = transactions.remove(tx);
256       if (modifications == null)
257       {
258          throw new Exception JavaDoc("transaction " + tx + " not found in transaction table");
259       }
260       put(modifications);
261    }
262
263    public void rollback(Object JavaDoc tx)
264    {
265       transactions.remove(tx);
266    }
267
268    /* ----------------------- Private methods ------------------------ */
269
270    File JavaDoc getDirectory(Fqn fqn, boolean create)
271    {
272       File JavaDoc f = new File JavaDoc(getFullPath(fqn));
273       if (!f.exists())
274       {
275          if (create)
276          {
277             f.mkdirs();
278          }
279          else
280          {
281             return null;
282          }
283       }
284       return f;
285    }
286
287
288    /**
289     * Recursively removes this and all subdirectories, plus all DATA files in them. To prevent damage, we only
290     * remove files that are named DATA (data.dat) and directories which end in ".fdb". If there is a dir or file
291     * that isn't named this way, the recursive removal will fail
292     *
293     * @return <code>true</code> if directory was removed,
294     * <code>false</code> if not.
295     */

296    boolean removeDirectory(File JavaDoc dir, boolean include_start_dir)
297    {
298       boolean success = true;
299       File JavaDoc[] subdirs = dir.listFiles();
300       for (int i = 0; i < subdirs.length; i++)
301       {
302          File JavaDoc file = subdirs[i];
303          if (file.isFile() && file.getName().equals(DATA))
304          {
305             if (!file.delete())
306             {
307                success = false;
308             }
309             continue;
310          }
311          if (file.isDirectory() && file.getName().endsWith(DIR_SUFFIX))
312          {
313             if (!removeDirectory(file, false))
314             {
315                success = false;
316             }
317             if (!file.delete())
318             {
319                success = false;
320             }
321          }
322       }
323
324       if (include_start_dir)
325       {
326          if (!dir.equals(root))
327          {
328             if (dir.delete())
329             {
330                return success;
331             }
332             success = false;
333          }
334       }
335
336       return success;
337    }
338
339    String JavaDoc getFullPath(Fqn fqn)
340    {
341       StringBuffer JavaDoc sb = new StringBuffer JavaDoc(rootPath);
342       for (int i = 0; i < fqn.size(); i++)
343       {
344          Object JavaDoc tmp = fqn.get(i);
345          // This is where we convert from Object to String!
346
String JavaDoc tmp_dir = tmp.toString(); // returns tmp.this if it's a String
347
sb.append(tmp_dir).append(".").append(DIR_SUFFIX).append(File.separator);
348       }
349       return sb.toString();
350    }
351
352    protected Map JavaDoc loadAttributes(Fqn fqn) throws Exception JavaDoc
353    {
354       File JavaDoc f = getDirectory(fqn, false);
355       if (f == null) return null; // i.e., this node does not exist.
356
// this node exists so we should never return a null after this... at worst case, an empty HashMap.
357
File JavaDoc child = new File JavaDoc(f, DATA);
358       if (!child.exists()) return new HashMap JavaDoc(0); // no node attribs exist hence the empty HashMap.
359
//if(!child.exists()) return null;
360
FileInputStream JavaDoc in = new FileInputStream JavaDoc(child);
361       MarshalledValueInputStream input = new MarshalledValueInputStream(in);
362       Map JavaDoc m = (Map JavaDoc) input.readObject();
363       in.close();
364       return m;
365    }
366
367    protected void storeAttributes(Fqn fqn, Map JavaDoc attrs) throws Exception JavaDoc
368    {
369       File JavaDoc f = getDirectory(fqn, true);
370       File JavaDoc child = new File JavaDoc(f, DATA);
371       if (!child.exists())
372       {
373          if (config.isCheckCharacterPortability())
374          {
375             /* Check whether the entire file path (root + fqn + data file name), is length portable */
376             isLengthPortablePath(child.getAbsolutePath());
377             /* Check whether the fqn tree we're trying to store could contain non portable characters */
378             isCharacterPortableTree(fqn);
379          }
380
381          if (!child.createNewFile())
382          {
383             throw new IOException JavaDoc("Unable to create file: " + child);
384          }
385       }
386       FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(child);
387       ObjectOutputStream JavaDoc output = new ObjectOutputStream JavaDoc(out);
388       output.writeObject(attrs);
389       out.close();
390    }
391
392    protected boolean isCharacterPortableLocation(String JavaDoc fileAbsolutePath)
393    {
394       Matcher JavaDoc matcher = PATH_PATTERN.matcher(fileAbsolutePath);
395       if (matcher.find())
396       {
397          log.warn("Cache loader location ( " + fileAbsolutePath + " ) contains one of these characters: '*' '<' '>' '|' '\"' '?'");
398          log.warn("Directories containing these characters are illegal in some operative systems and could lead to portability issues");
399          return false;
400       }
401
402       return true;
403    }
404
405    protected boolean isCharacterPortableTree(Fqn fqn)
406    {
407       List JavaDoc elements = fqn.peekElements();
408       // Don't assume the Fqn is composed of Strings!!
409
for (Object JavaDoc anElement : elements)
410       {
411          // getFullPath converts Object to String via toString(), so we do too
412
Matcher JavaDoc matcher = FQN_PATTERN.matcher(anElement.toString());
413          if (matcher.find())
414          {
415             log.warn("One of the Fqn ( " + fqn + " ) elements contains one of these characters: '*' '<' '>' '|' '\"' '?' '\\' '/' ':' ");
416             log.warn("Directories containing these characters are illegal in some operating systems and could lead to portability issues");
417             return false;
418          }
419       }
420
421       return true;
422    }
423
424    protected boolean isLengthPortablePath(String JavaDoc absoluteFqnPath)
425    {
426       if (absoluteFqnPath.length() > 255)
427       {
428          log.warn("The full absolute path to the fqn that you are trying to store is bigger than 255 characters, this could lead to problems in Windows systems: " + absoluteFqnPath);
429          return false;
430       }
431
432       return true;
433    }
434 }
435
Popular Tags