KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > remoting > CallbackStore


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.remoting;
8
9 import org.jboss.logging.Logger;
10
11 import java.io.File JavaDoc;
12 import java.io.FileInputStream JavaDoc;
13 import java.io.FileOutputStream JavaDoc;
14 import java.io.FilenameFilter JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.ObjectInputStream JavaDoc;
17 import java.io.ObjectOutputStream JavaDoc;
18 import java.io.Serializable JavaDoc;
19 import java.util.Map JavaDoc;
20
21 /**
22  * Acts as a persistent list which writes Serializable objects to disk and will retrieve them
23  * in same order in which they were added (FIFO). Each file will be named according to the current
24  * time (using System.currentTimeMillis() with the file suffix specified (see below). When the
25  * object is read and returned by calling the getNext() method, the file on disk for that object will
26  * be deleted. If for some reason the store VM crashes, the objects will still be available upon next startup.
27  * <p/>
28  * The attributes to make sure to configure are:
29  * <p/>
30  * file path - this determins which directory to write the objects. The default value is the property value
31  * of 'jboss.server.data.dir' and if this is not set, then will be 'data'. For example, might
32  * be /jboss/server/default/data.<p>
33  * file suffix - the file suffix to use for the file written for each object stored.<p>
34  * <p/>
35  * This is also a service mbean, so can be run as a service within JBoss AS or stand alone.
36  *
37  * @author <a HREF="mailto:tom@jboss.org">Tom Elrod</a>
38  */

39 public class CallbackStore implements CallbackStoreMBean
40 {
41    private String JavaDoc filePath = null;
42    private String JavaDoc fileSuffix = "ser";
43
44    private boolean isStarted = false;
45    private boolean purgeOnShutdown = false;
46
47    public static final String JavaDoc FILE_PATH_KEY = "StoreFilePath";
48    public static final String JavaDoc FILE_SUFFIX_KEY = "StoreFileSuffix";
49
50    private static final Logger log = Logger.getLogger(CallbackStore.class);
51
52    /**
53     * Default store constructor.
54     */

55    public CallbackStore()
56    {
57
58    }
59
60    /**
61     * Store constructor.
62     * @param purgeOnDestroy if true, will remove all persisted objects from disk on when destroy() is called, else
63     * will leave the files (which is the default behaviour).
64     */

65    public CallbackStore(boolean purgeOnDestroy)
66    {
67       this.purgeOnShutdown = purgeOnDestroy;
68    }
69
70    /**
71     * Will get the file path value (if not already set will just use the
72     * default setting) and will create the directory specified by the file path
73     * if it does not already exist.
74     *
75     * @throws Exception
76     */

77    public void start() throws Exception JavaDoc
78    {
79       if(!isStarted)
80       {
81          // need to figure the best place to store on disk
82
if(filePath == null)
83          {
84             filePath = System.getProperty("jboss.server.data.dir", "data");
85          }
86          File JavaDoc storeFile = new File JavaDoc(filePath);
87          if(!storeFile.exists())
88          {
89             boolean madeDir = storeFile.mkdirs();
90             if(!madeDir)
91             {
92                throw new IOException JavaDoc("Can not create directory for store. Path given: " + filePath);
93             }
94          }
95          isStarted = true;
96       }
97    }
98
99    /**
100     * Sets if store should clean up persisted files when shutdown (destroy()).
101     * @param purgeOnShutdown
102     */

103    public void setPurgeOnShutdown(boolean purgeOnShutdown)
104    {
105       this.purgeOnShutdown = purgeOnShutdown;
106    }
107
108    /**
109     * Returns if store will clean up persisted files when shutdown (destroy()).
110     * @return
111     */

112    public boolean getPurgeOnShutdown()
113    {
114       return purgeOnShutdown;
115    }
116
117    /**
118     * This is a no op method, but needed in order to be used as a service within JBoss AS.
119     *
120     * @throws Exception
121     */

122    public void create() throws Exception JavaDoc
123    {
124    }
125
126    /**
127     * This will allow for change of file suffix and file path and then may start again
128     * using these new values. However, any object already written out using the old
129     * values will be lost as will not longer be accessible if these attributes are changed while stopped.
130     */

131    public void stop()
132    {
133       isStarted = false;
134    }
135
136    /**
137     * If purgeOnDestroy is true, will remove files upon shutdown.
138     */

139    public void destroy()
140    {
141       if(purgeOnShutdown)
142       {
143          purgeFiles();
144       }
145    }
146
147    public void purgeFiles()
148    {
149       String JavaDoc[] fileList = getObjectFileList();
150       String JavaDoc fileToDelete = null;
151       for(int x = 0; x < fileList.length; x++)
152       {
153          try
154          {
155             fileToDelete = filePath + System.getProperty("file.separator") + fileList[x];
156             File JavaDoc currentFile = new File JavaDoc(fileToDelete);
157             boolean deleted = currentFile.delete();
158             if(!deleted)
159             {
160                log.warn("Error purging file " + fileToDelete);
161             }
162          }
163          catch(Exception JavaDoc e)
164          {
165             log.warn("Error purging file " + fileToDelete);
166          }
167       }
168    }
169
170    /**
171     * Will use the values in the map to set configuration. This will not change behaviour of store until
172     * has been stopped and then started (if has not been started, will take effect upon start).
173     * The keys for the map are FILE_PATH_KEY and FILE_SUFFIX_KEY.
174     *
175     * @param config
176     */

177    public void setConfig(Map JavaDoc config)
178    {
179       if(config != null)
180       {
181          String JavaDoc newFilePath = (String JavaDoc) config.get(FILE_PATH_KEY);
182          if(newFilePath != null)
183          {
184             filePath = newFilePath;
185          }
186          String JavaDoc newFileSuffix = (String JavaDoc) config.get(FILE_SUFFIX_KEY);
187          if(newFileSuffix != null)
188          {
189             fileSuffix = newFileSuffix;
190          }
191       }
192    }
193
194    /**
195     * Gets the file path for the directory where the objects will be stored.
196     *
197     * @return
198     */

199    public String JavaDoc getStoreFilePath()
200    {
201       return filePath;
202    }
203
204    /**
205     * Sets teh file path for the directory where the objects will be stored.
206     *
207     * @param filePath
208     */

209    public void setStoreFilePath(String JavaDoc filePath)
210    {
211       this.filePath = filePath;
212    }
213
214    /**
215     * Gets the file suffix for each of the files that objects will be persisted to.
216     *
217     * @return
218     */

219    public String JavaDoc getStoreFileSuffix()
220    {
221       return fileSuffix;
222    }
223
224    /**
225     * Sets the file suffix for each of the files that objects will be persisted to.
226     *
227     * @param fileSuffix
228     */

229    public void setStoreFileSuffix(String JavaDoc fileSuffix)
230    {
231       this.fileSuffix = fileSuffix;
232    }
233
234
235    /**
236     * Getst the number of objects stored and available.
237     *
238     * @return
239     */

240    public int size()
241    {
242       verifyStarted();
243       String JavaDoc[] objectFileList = getObjectFileList();
244       if(objectFileList != null)
245       {
246          return objectFileList.length;
247       }
248       else
249       {
250          return 0;
251       }
252    }
253
254    private void verifyStarted()
255    {
256       if(!isStarted)
257       {
258          throw new RuntimeException JavaDoc("Can not call upon this store method before it has been started.");
259       }
260    }
261
262    /**
263     * Will look through the files in the store directory for the oldest object serialized to disk, load it,
264     * delete the file, and return the deserialized object.
265     * Important to note that once this object is returned from this method, it is gone forever from this
266     * store and will not be able to retrieve it again without adding it back.
267     *
268     * @return
269     * @throws IOException
270     */

271    public Object JavaDoc getNext() throws IOException JavaDoc
272    {
273       verifyStarted();
274
275       Object JavaDoc obj = null;
276       String JavaDoc objectFilePath = null;
277
278       synchronized(filePath)
279       {
280          String JavaDoc[] objectFileList = getObjectFileList();
281          FileInputStream JavaDoc inFile = null;
282          ObjectInputStream JavaDoc in = null;
283
284          if(objectFileList != null && objectFileList.length > 0)
285          {
286             try
287             {
288                // only getting the first one, which will be first one entered since the getting
289
// of the list is automatically ordered by the OS and all file names are numeric by time.
290
objectFilePath = filePath + System.getProperty("file.separator") + objectFileList[0];
291                inFile = new FileInputStream JavaDoc(objectFilePath);
292                in = new ObjectInputStream JavaDoc(inFile);
293                try
294                {
295                   obj = in.readObject();
296                }
297                catch(ClassNotFoundException JavaDoc e)
298                {
299                   throw new IOException JavaDoc("Error loading persisted object. Could not load class (" + e.getMessage() + ").");
300                }
301             }
302             finally
303             {
304                if(inFile != null)
305                {
306                   try
307                   {
308                      inFile.close();
309                   }
310                   catch(IOException JavaDoc ioe)
311                   {
312                      log.debug("Error closing FileInputStream.", ioe);
313                   }
314                }
315                if(in != null)
316                {
317                   try
318                   {
319                      in.close();
320                   }
321                   catch(IOException JavaDoc ioe)
322                   {
323                      log.debug("Error closing ObjectInputStream.", ioe);
324                   }
325                }
326             }
327          }
328       }
329
330       if(objectFilePath != null)
331       {
332          // now remove the file
333
File JavaDoc objectFile = new File JavaDoc(objectFilePath);
334          boolean isDeleted = objectFile.delete();
335          if(log.isTraceEnabled())
336          {
337             log.trace("object file (" + objectFilePath + ") has been deleted - " + isDeleted);
338          }
339       }
340
341       return obj;
342    }
343
344    private String JavaDoc[] getObjectFileList()
345    {
346       File JavaDoc storePath = new File JavaDoc(filePath);
347       String JavaDoc[] objectFileList = storePath.list(new StoreFileFilter());
348       return objectFileList;
349    }
350
351    /**
352     * Persists the serializable object passed to the directory specified. The file name will be the current time
353     * in milliseconds (vis System.currentTimeMillis()) with the specified suffix. This object can later be
354     * retrieved using the getNext() method, but objects will be returned in the order that they were added (FIFO).
355     *
356     * @param object
357     * @throws IOException
358     */

359    public void add(Serializable JavaDoc object) throws IOException JavaDoc
360    {
361       verifyStarted();
362
363       synchronized(filePath)
364       {
365          long currentTimestamp = System.currentTimeMillis();
366          File JavaDoc storeFile = new File JavaDoc(filePath + System.getProperty("file.separator") + String.valueOf(currentTimestamp) + "." + fileSuffix);
367          FileOutputStream JavaDoc outFile = null;
368          ObjectOutputStream JavaDoc out = null;
369
370          try
371          {
372             outFile = new FileOutputStream JavaDoc(storeFile, false);
373             out = new ObjectOutputStream JavaDoc(outFile);
374             out.writeObject(object);
375             out.flush();
376          }
377          finally
378          {
379             if(outFile != null)
380             {
381                try
382                {
383                   outFile.close();
384                }
385                catch(IOException JavaDoc ioe)
386                {
387                   log.debug("Error closing FileInputStream.", ioe);
388                }
389             }
390             if(out != null)
391             {
392                try
393                {
394                   out.close();
395                }
396                catch(IOException JavaDoc ioe)
397                {
398                   log.debug("Error closing ObjectInputStream.", ioe);
399                }
400             }
401
402          }
403       }
404    }
405
406    public class StoreFileFilter implements FilenameFilter JavaDoc
407    {
408       /**
409        * Tests if a specified file should be included in a file list.
410        *
411        * @param dir the directory in which the file was found.
412        * @param name the name of the file.
413        * @return <code>true</code> if and only if the name should be included in the file list; <code>false</code>
414        * otherwise.
415        */

416       public boolean accept(File JavaDoc dir, String JavaDoc name)
417       {
418          if(name.endsWith(fileSuffix))
419          {
420             return true;
421          }
422          else
423          {
424             return false;
425          }
426       }
427    }
428
429 }
430
Popular Tags