View Javadoc

1   /*
2    * $Id: FilePersistenceStrategy.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util.queue;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.context.MuleContextAware;
16  import org.mule.api.transformer.wire.WireFormat;
17  import org.mule.transformer.wire.SerializationWireFormat;
18  import org.mule.util.FileUtils;
19  import org.mule.util.UUID;
20  import org.mule.util.file.DeleteException;
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.List;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  public class FilePersistenceStrategy implements QueuePersistenceStrategy, MuleContextAware
37  {
38      private static final Log logger = LogFactory.getLog(FilePersistenceStrategy.class);
39  
40     /** The default queueStore directory for persistence */
41     public static final String DEFAULT_QUEUE_STORE = "queuestore";
42      
43      public static final String EXTENSION = ".msg";
44  
45      private File store;
46  
47      protected MuleContext muleContext;
48  
49      private WireFormat serializer;
50  
51      public FilePersistenceStrategy(WireFormat serializer)
52      {
53          super();
54          this.serializer = serializer;
55      }
56  
57      public FilePersistenceStrategy()
58      {
59          this(new SerializationWireFormat());
60      }
61  
62      public void setMuleContext(MuleContext context)
63      {
64          this.muleContext = context;
65  
66          serializer.setMuleContext(muleContext);
67      }
68  
69      public Object store(String queue, Object obj) throws IOException
70      {
71          String id = UUID.getAscendingOrderUUID();
72          
73          String filename = queue + File.separator + id + EXTENSION;
74          File file = FileUtils.newFile(store, filename);
75          
76          if (!file.getParentFile().exists())
77          {
78              createStoreDirectory(file.getParentFile());
79          }
80          
81          OutputStream out = new FileOutputStream(file);
82          try
83          {
84              serializer.write(out, obj, muleContext.getConfiguration().getDefaultEncoding());
85          }
86          catch (MuleException e)
87          {
88              IOException iox = new IOException();
89              iox.initCause(e);
90              throw iox;
91          }
92          finally
93          {
94              out.close();
95          }
96          
97          return id;
98      }
99      
100     protected synchronized void createStoreDirectory(File direcetory) throws IOException
101     {
102         // To support concurrency we need to check if directory exists again inside
103         // synchronized method
104         if (!direcetory.exists() && !direcetory.mkdirs())
105         {
106             throw new IOException("Failed to create directory: " + direcetory.getAbsolutePath());
107         }
108     }
109 
110     public void remove(String queue, Object id) throws IOException
111     {
112         String fileName = queue + File.separator + id + EXTENSION;
113         File file = FileUtils.newFile(store, fileName);
114         if (file.exists())
115         {
116             if (!file.delete())
117             {
118                 throw new DeleteException(file);
119             }
120         }
121         else
122         {
123             throw new FileNotFoundException(file.getAbsolutePath());
124         }
125     }
126 
127     public Object load(String queue, Object id) throws IOException
128     {
129         String fileName = queue + File.separator + id + EXTENSION;
130         File file = FileUtils.newFile(store, fileName);
131 
132         InputStream in = new FileInputStream(file);
133         try
134         {
135             return serializer.read(in);
136         }
137         catch (MuleException e)
138         {
139             IOException iox = new IOException(e.getDetailedMessage());
140             iox.initCause(e);
141             throw iox;
142         }
143         finally
144         {
145             in.close();
146         }
147     }
148 
149     public List<Holder> restore() throws IOException
150     {
151         List<Holder> msgs = new ArrayList<Holder>();
152         if (store == null)
153         {
154             logger.warn("No store has be set on the File Persistence Strategy. Not restoring at this time");
155             return msgs;
156         }
157         
158         try
159         {
160             restoreFiles(store, msgs);
161             
162             if (logger.isDebugEnabled())
163             {
164                 logger.debug("Restore retrieved " + msgs.size() + " objects");
165             }
166             
167             return msgs;
168         }
169         catch (ClassNotFoundException e)
170         {
171             throw (IOException) new IOException("Could not restore").initCause(e);
172         }
173     }
174 
175     protected void restoreFiles(File dir, List<Holder> msgs) throws IOException, ClassNotFoundException
176     {
177         File[] files = dir.listFiles();
178         if (files == null)
179         {
180             return;
181         }
182         // sort the files so they are in the order in which
183         // their ids were generated in method store()
184         Arrays.sort(files);
185         for (int i = 0; i < files.length; i++)
186         {
187             if (files[i].isDirectory())
188             {
189                 restoreFiles(files[i], msgs);
190             }
191             else if (files[i].getName().endsWith(EXTENSION))
192             {
193                 String id = files[i].getCanonicalPath();
194                 id = id.substring(store.getCanonicalPath().length() + 1, id.length() - EXTENSION.length());
195                 String queue = id.substring(0, id.indexOf(File.separator));
196                 id = id.substring(queue.length() + 1);
197                 msgs.add(new HolderImpl(queue, id));
198             }
199         }
200     }
201 
202     public void open() throws IOException
203     {
204         String path = muleContext.getConfiguration().getWorkingDirectory() + File.separator + DEFAULT_QUEUE_STORE;
205         store = FileUtils.newFile(path).getCanonicalFile();
206         if (!store.exists())
207         {
208             createStoreDirectory(store);
209         }
210     }
211 
212     public void close() throws IOException
213     {
214         // Nothing to do
215     }
216 
217     protected static class HolderImpl implements Holder
218     {
219         private String queue;
220         private Object id;
221 
222         public HolderImpl(String queue, Object id)
223         {
224             this.queue = queue;
225             this.id = id;
226         }
227 
228         public Object getId()
229         {
230             return id;
231         }
232 
233         public String getQueue()
234         {
235             return queue;
236         }
237     }
238 
239     public boolean isTransient()
240     {
241         return false;
242     }
243 }