KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > store > FilesystemStore


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.components.store;
17
18 import org.apache.avalon.framework.CascadingRuntimeException;
19 import org.apache.avalon.framework.context.Context;
20 import org.apache.avalon.framework.context.ContextException;
21 import org.apache.avalon.framework.context.Contextualizable;
22 import org.apache.avalon.framework.logger.AbstractLogEnabled;
23 import org.apache.avalon.framework.thread.ThreadSafe;
24 import org.apache.avalon.framework.parameters.Parameterizable;
25 import org.apache.avalon.framework.parameters.Parameters;
26 import org.apache.avalon.framework.parameters.ParameterException;
27 import org.apache.cocoon.Constants;
28 import org.apache.cocoon.util.IOUtils;
29 import java.io.ByteArrayOutputStream JavaDoc;
30 import java.io.File JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.OutputStreamWriter JavaDoc;
33 import java.util.BitSet JavaDoc;
34 import java.util.Enumeration JavaDoc;
35
36 /**
37  * Stores objects on the filesystem: String objects as text files,
38  * all other objects are serialized.
39  *
40  * @deprecated Use the {@link org.apache.cocoon.components.store.impl.FilesystemStore}
41  *
42  * @author ?
43  * @author <a HREF="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
44  * @version CVS $Id: FilesystemStore.java 53913 2004-10-06 21:37:44Z antonio $
45  */

46 public final class FilesystemStore extends AbstractLogEnabled
47     implements Store, Contextualizable, Parameterizable, ThreadSafe {
48
49     protected File JavaDoc workDir;
50     protected File JavaDoc cacheDir;
51
52     /** The directory repository */
53     protected File JavaDoc directoryFile;
54     protected volatile String JavaDoc directoryPath;
55
56     /**
57      * Sets the repository's location
58      */

59     public void setDirectory(final String JavaDoc directory)
60     throws IOException JavaDoc {
61         this.setDirectory(new File JavaDoc(directory));
62     }
63
64     public void contextualize(final Context context)
65     throws ContextException {
66         this.workDir = (File JavaDoc)context.get(Constants.CONTEXT_WORK_DIR);
67         this.cacheDir = (File JavaDoc)context.get(Constants.CONTEXT_CACHE_DIR);
68     }
69
70     public void parameterize(Parameters params)
71     throws ParameterException {
72         try {
73             if (params.getParameterAsBoolean("use-cache-directory", false)) {
74                 if (this.getLogger().isDebugEnabled())
75                     getLogger().debug("Using cache directory: " + cacheDir);
76                 setDirectory(cacheDir);
77             } else if (params.getParameterAsBoolean("use-work-directory", false)) {
78                 if (this.getLogger().isDebugEnabled())
79                     getLogger().debug("Using work directory: " + workDir);
80                 setDirectory(workDir);
81             } else if (params.getParameter("directory", null) != null) {
82                 String JavaDoc dir = params.getParameter("directory");
83                 dir = IOUtils.getContextFilePath(workDir.getPath(), dir);
84                 if (this.getLogger().isDebugEnabled())
85                     getLogger().debug("Using directory: " + dir);
86                 setDirectory(new File JavaDoc(dir));
87             } else {
88                 try {
89                     // Legacy: use working directory by default
90
setDirectory(workDir);
91                 } catch (IOException JavaDoc e) {
92                     // Legacy: Always was ignored
93
}
94             }
95         } catch (IOException JavaDoc e) {
96             throw new ParameterException("Unable to set directory", e);
97         }
98     }
99
100     /**
101      * Sets the repository's location
102      */

103     public void setDirectory(final File JavaDoc directory)
104     throws IOException JavaDoc {
105         this.directoryFile = directory;
106
107         /* Save directory path prefix */
108         this.directoryPath = IOUtils.getFullFilename(this.directoryFile);
109         this.directoryPath += File.separator;
110
111         /* Does directory exist? */
112         if (!this.directoryFile.exists()) {
113             /* Create it anew */
114             if (!this.directoryFile.mkdir()) {
115                 throw new IOException JavaDoc(
116                 "Error creating store directory '" + this.directoryPath + "': ");
117             }
118         }
119
120         /* Is given file actually a directory? */
121         if (!this.directoryFile.isDirectory()) {
122             throw new IOException JavaDoc("'" + this.directoryPath + "' is not a directory");
123         }
124
125         /* Is directory readable and writable? */
126         if (!(this.directoryFile.canRead() && this.directoryFile.canWrite())) {
127             throw new IOException JavaDoc(
128                 "Directory '" + this.directoryPath + "' is not readable/writable"
129             );
130         }
131     }
132
133     /**
134      * Returns the repository's full pathname
135      */

136     public String JavaDoc getDirectoryPath() {
137         return this.directoryPath;
138     }
139
140     /**
141      * Get the File object associated with the given unique key name.
142      */

143     public synchronized Object JavaDoc get(final Object JavaDoc key) {
144         final File JavaDoc file = fileFromKey(key);
145
146         if (file != null && file.exists()) {
147             if (this.getLogger().isDebugEnabled()) {
148                 getLogger().debug("Found file: " + key);
149             }
150             try {
151                 return IOUtils.deserializeObject(file);
152             } catch (Exception JavaDoc any) {
153                 getLogger().error("Error during deseralization.", any);
154             }
155         } else {
156             if (this.getLogger().isDebugEnabled()) {
157                 getLogger().debug("NOT Found file: " + key);
158             }
159         }
160
161         return null;
162     }
163
164     /**
165      * Store the given object in a persistent state.
166      * 1) Null values generate empty directories.
167      * 2) String values are dumped to text files
168      * 3) Object values are serialized
169      */

170     public synchronized void store(final Object JavaDoc key, final Object JavaDoc value)
171     throws IOException JavaDoc {
172         final File JavaDoc file = fileFromKey(key);
173
174         /* Create subdirectories as needed */
175         final File JavaDoc parent = file.getParentFile();
176         if (parent != null) {
177             parent.mkdirs();
178         }
179
180         /* Store object as file */
181         if (value == null) { /* Directory */
182             if (file.exists()) {
183                 if (!file.delete()) { /* FAILURE */
184                     getLogger().error("File cannot be deleted: " + file.toString());
185                     return;
186                 }
187             }
188
189             file.mkdir();
190         } else if (value instanceof String JavaDoc) {
191             /* Text file */
192             IOUtils.serializeString(file, (String JavaDoc) value);
193         } else {
194             /* Serialized Object */
195             IOUtils.serializeObject(file, value);
196         }
197     }
198
199     /**
200      * Holds the given object in a volatile state.
201      */

202     public synchronized void hold(final Object JavaDoc key, final Object JavaDoc value)
203     throws IOException JavaDoc {
204         this.store(key, value);
205         final File JavaDoc file = this.fileFromKey(key);
206         if (file != null) {
207           file.deleteOnExit();
208         }
209     }
210
211     /**
212      * Remove the object associated to the given key.
213      */

214     public synchronized void remove(final Object JavaDoc key) {
215         final File JavaDoc file = fileFromKey(key);
216         if (file != null) {
217             file.delete();
218         }
219     }
220
221     /**
222      * Indicates if the given key is associated to a contained object.
223      */

224     public synchronized boolean containsKey(final Object JavaDoc key) {
225         final File JavaDoc file = fileFromKey(key);
226         if (file == null) {
227             return false;
228         }
229         return file.exists();
230     }
231
232     /**
233      * Returns the list of stored files as an Enumeration of Files
234      */

235     public synchronized Enumeration JavaDoc keys() {
236         final FSEnumeration fsEnum = new FSEnumeration();
237         this.addKeys(fsEnum, this.directoryFile);
238         return fsEnum;
239     }
240
241     /**
242      * Returns count of the objects in the store, or -1 if could not be
243      * obtained.
244      */

245     public synchronized int size() {
246         return countKeys(this.directoryFile);
247     }
248
249     protected void addKeys(FSEnumeration fsEnum, File JavaDoc directory) {
250         final int subStringBegin = this.directoryFile.getAbsolutePath().length() + 1;
251         final File JavaDoc[] files = directory.listFiles();
252         for (int i=0; i<files.length; i++) {
253             if (files[i].isDirectory()) {
254                 this.addKeys(fsEnum, files[i]);
255             } else {
256                 fsEnum.add(this.decode(files[i].getAbsolutePath().substring(subStringBegin)));
257             }
258         }
259     }
260
261     protected int countKeys(File JavaDoc directory) {
262         int count = 0;
263         final File JavaDoc[] files = directory.listFiles();
264         for (int i=0; i<files.length; i++) {
265             if (files[i].isDirectory()) {
266                 count += this.countKeys(files[i]);
267             } else {
268                 count ++;
269             }
270         }
271         return count;
272     }
273
274     final class FSEnumeration implements Enumeration JavaDoc {
275         private String JavaDoc[] array;
276         private int index;
277         private int length;
278
279         FSEnumeration() {
280             this.array = new String JavaDoc[16];
281             this.length = 0;
282             this.index = 0;
283         }
284
285         public void add(String JavaDoc key) {
286             if (this.length == array.length) {
287                 String JavaDoc[] newarray = new String JavaDoc[this.length + 16];
288                 System.arraycopy(this.array, 0, newarray, 0, this.array.length);
289                 this.array = newarray;
290             }
291             this.array[this.length] = key;
292             this.length++;
293         }
294
295         public boolean hasMoreElements() {
296             return (this.index < this.length);
297         }
298
299         public Object JavaDoc nextElement() {
300             if (this.hasMoreElements()) {
301                 this.index++;
302                 return this.array[index-1];
303             }
304             return null;
305         }
306     }
307
308     /* Utility Methods*/
309     protected File JavaDoc fileFromKey(final Object JavaDoc key) {
310         return IOUtils.createFile(this.directoryFile, this.encode(key.toString()));
311     }
312
313     public String JavaDoc getString(final Object JavaDoc key)
314     throws IOException JavaDoc {
315         final File JavaDoc file = this.fileFromKey(key);
316         if (file != null) {
317             return IOUtils.deserializeString(file);
318         }
319
320         return null;
321     }
322
323     public synchronized void free() {}
324
325     public synchronized Object JavaDoc getObject(final Object JavaDoc key)
326     throws IOException JavaDoc, ClassNotFoundException JavaDoc
327     {
328         final File JavaDoc file = this.fileFromKey(key);
329         if (file != null) {
330             return IOUtils.deserializeObject(file);
331         }
332
333         return null;
334     }
335
336     /**
337      * Inverse of encode exept it do not use path.
338      * So decode(encode(s) - m_path) = s.
339      * In other words it returns a String that can be used as key to retive
340      * the record contained in the 'filename' file.
341      */

342     protected String JavaDoc decode( String JavaDoc filename )
343     {
344         try {
345             return java.net.URLDecoder.decode( filename );
346         } catch (Exception JavaDoc local) {
347             throw new CascadingRuntimeException("Exception in decode", local);
348         }
349     }
350
351     /** A BitSet defining the characters which don't need encoding */
352     static BitSet JavaDoc charactersDontNeedingEncoding;
353     static final int characterCaseDiff = ('a' - 'A');
354
355     /** Initialize the BitSet */
356     static
357     {
358         charactersDontNeedingEncoding = new BitSet JavaDoc(256);
359         int i;
360         for (i = 'a'; i <= 'z'; i++)
361         {
362             charactersDontNeedingEncoding.set(i);
363         }
364         for (i = 'A'; i <= 'Z'; i++)
365         {
366             charactersDontNeedingEncoding.set(i);
367         }
368         for (i = '0'; i <= '9'; i++)
369         {
370             charactersDontNeedingEncoding.set(i);
371         }
372         charactersDontNeedingEncoding.set('-');
373         charactersDontNeedingEncoding.set('_');
374         charactersDontNeedingEncoding.set('(');
375         charactersDontNeedingEncoding.set(')');
376     }
377
378     /**
379      * Returns a String that uniquely identifies the object.
380      * <b>Note:</b> since this method uses the Object.toString()
381      * method, it's up to the caller to make sure that this method
382      * doesn't change between different JVM executions (like
383      * it may normally happen). For this reason, it's highly recommended
384      * (even if not mandated) that Strings be used as keys.
385      */

386     public String JavaDoc encode(String JavaDoc s) {
387         final StringBuffer JavaDoc out = new StringBuffer JavaDoc( s.length() );
388         final ByteArrayOutputStream JavaDoc buf = new ByteArrayOutputStream JavaDoc( 32 );
389         final OutputStreamWriter JavaDoc writer = new OutputStreamWriter JavaDoc( buf );
390         for (int i = 0; i < s.length(); i++)
391         {
392             int c = s.charAt(i);
393             if (charactersDontNeedingEncoding.get(c))
394             {
395                 out.append((char)c);
396             }
397             else
398             {
399                 try
400                 {
401                     writer.write(c);
402                     writer.flush();
403                 }
404                 catch(IOException JavaDoc e)
405                 {
406                     buf.reset();
407                     continue;
408                 }
409                 byte[] ba = buf.toByteArray();
410                 for (int j = 0; j < ba.length; j++)
411                 {
412                     out.append('%');
413                     char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
414                     // converting to use uppercase letter as part of
415
// the hex value if ch is a letter.
416
if (Character.isLetter(ch))
417                     {
418                         ch -= characterCaseDiff;
419                     }
420                     out.append(ch);
421                     ch = Character.forDigit(ba[j] & 0xF, 16);
422                     if (Character.isLetter(ch))
423                     {
424                         ch -= characterCaseDiff;
425                     }
426                     out.append(ch);
427                 }
428                 buf.reset();
429             }
430         }
431
432         return out.toString();
433     }
434 }
435
Popular Tags