View Javadoc

1   package uk.ac.cam.spectra.spectrasub;
2   
3   import java.io.File;
4   import java.io.FileInputStream;
5   import java.io.FileNotFoundException;
6   import java.io.FileOutputStream;
7   import java.io.IOException;
8   import java.io.ObjectInputStream;
9   import java.io.ObjectOutputStream;
10  import java.util.HashMap;
11  import java.util.Map;
12  import java.util.UUID;
13  
14  import org.apache.commons.io.IOUtils;
15  import org.apache.log4j.Logger;
16  
17  import uk.ac.cam.spectra.DataFileType;
18  import uk.ac.cam.spectra.Util;
19  
20  import com.hp.hpl.jena.rdf.model.Model;
21  import com.hp.hpl.jena.rdf.model.ModelFactory;
22  
23  public class DataPackageDAO {
24  
25      private static final String WORK_DIR_NAME = "work";
26  
27      private static final String PKG_DIR_NAME = "packages";
28  
29      private static final String STATE_SER = "state.ser";
30  
31      private static final Logger LOG = Logger.getLogger(DataPackageDAO.class);
32  
33      private static final String METADATA_SER = "metadata.n3";
34  
35      String storageBase;
36  
37      private File storageDir;
38  
39      private boolean init;
40  
41      /**
42       * Lookup of type names to datafile type classes. To be configured by IoC
43       * container.
44       */
45      private Map<String, DataFileType> type = new HashMap<String, DataFileType>();
46  
47      public Map<String, DataFileType> getType() {
48          return type;
49      }
50  
51      public void setType(Map<String, DataFileType> type) {
52          this.type = type;
53      }
54  
55      public String getStorageBase() {
56          return storageBase;
57      }
58  
59      public void setStorageBase(String storageBase) {
60          this.storageBase = storageBase;
61      }
62  
63      public synchronized void init() {
64          storageDir = new File(storageBase);
65          if (!storageDir.exists()) {
66              if (!storageDir.mkdirs()) {
67                  throw new IllegalStateException(storageDir
68                          + " does not exist and cannot create it");
69              }
70          }
71          if (!storageDir.isDirectory()) {
72              throw new IllegalStateException(storageDir + " is not a directory");
73          }
74          if (!storageDir.canWrite()) {
75              throw new IllegalStateException("Cannot write to " + storageDir);
76          }
77          init = true;
78      }
79  
80      private void checkInit() {
81          if (!init) {
82              throw new IllegalStateException("DAO not initialized");
83          }
84      }
85  
86      public String save(DataPackage pkg) {
87          checkInit();
88          if (pkg.getId() == null) {
89              String id = UUID.randomUUID().toString();
90              pkg.setId(id);
91          }
92          File pkgDir = new File(storageBase, pkg.getId());
93          if (!pkgDir.exists()) {
94              pkgDir.mkdirs();
95          }
96  
97          File workDir = new File(pkgDir, WORK_DIR_NAME);
98          if (!workDir.exists()) {
99              workDir.mkdirs();
100         }
101         pkg.setUri(workDir.toURI());
102 
103         FileOutputStream stateOutS = null;
104         ObjectOutputStream stateObjOutS = null;
105         FileOutputStream mdOutS = null;
106         File stateF = new File(workDir, STATE_SER);
107         boolean createStateBackup = stateF.exists();
108         File stateBak = null;
109         if (createStateBackup) {
110             stateBak = new File(workDir, STATE_SER + ".bak");
111             try {
112                 backup(stateF, stateBak);
113             } catch (IOException e) {
114                 throw new RuntimeException("Could not create data backup: "
115                         + e.getMessage(), e);
116             }
117         }
118         File mdF = new File(workDir, METADATA_SER);
119         boolean createMDBackup = mdF.exists();
120         File mdBak = null;
121         if (createMDBackup) {
122             mdBak = new File(workDir, METADATA_SER + ".bak");
123             try {
124                 backup(mdF, mdBak);
125             } catch (IOException e) {
126                 throw new RuntimeException("Could not create metadata backup: "
127                         + e.getMessage(), e);
128             }
129         }
130 
131         try {
132             // Serialize the package object
133             stateF.createNewFile();
134             stateOutS = new FileOutputStream(stateF);
135             stateObjOutS = new ObjectOutputStream(stateOutS);
136             stateObjOutS.writeObject(pkg);
137             // Write the metadata to file.
138             mdF.createNewFile();
139             LOG.debug("Writing metadata (" + pkg.getMetadata().size()
140                     + " statements) to " + mdF);
141             mdOutS = new FileOutputStream(mdF);
142             pkg.getMetadata().write(mdOutS, "N3");
143         } catch (FileNotFoundException e) {
144             if (createStateBackup) {
145                 restore(stateBak, stateF);
146             }
147             if (createMDBackup) {
148                 restore(mdBak, mdF);
149             }
150             LOG.error("Unexpected problem: " + e.getMessage(), e);
151             throw new RuntimeException("Unexpected problem: " + e.getMessage(),
152                     e);
153         } catch (IOException e) {
154             if (createStateBackup) {
155                 restore(stateBak, stateF);
156             }
157             if (createMDBackup) {
158                 restore(mdBak, mdF);
159             }
160             LOG.error("Problem storing data: " + e.getMessage(), e);
161             throw new RuntimeException("Problem storing data: "
162                     + e.getMessage(), e);
163         } finally {
164             IOUtils.closeQuietly(stateOutS);
165             IOUtils.closeQuietly(stateObjOutS);
166             IOUtils.closeQuietly(mdOutS);
167         }
168         return pkg.getId();
169     }
170 
171     private void backup(File of, File backup) throws IOException {
172         if (of.exists()) {
173             Util.move(of, backup);
174             of.delete();
175             of.createNewFile();
176         }
177     }
178 
179     private void restore(File backup, File of) {
180         try {
181             Util.move(backup, of);
182         } catch (IOException e) {
183             LOG.warn(e);
184         }
185     }
186 
187     public DataPackage load(String id) throws NotFoundException {
188         File pkgDir = new File(storageDir, id);
189         File workDir = new File(pkgDir, WORK_DIR_NAME);
190         File stateF = new File(workDir, STATE_SER);
191         if (!stateF.exists()) {
192             throw new NotFoundException(
193                     "No state file for DataPackage with id " + id + " exists",
194                     id);
195         }
196         File mdF = new File(workDir, METADATA_SER);
197         if (!mdF.exists()) {
198             throw new NotFoundException(
199                     "No metadata file for DataPackage with id " + id
200                             + " exists", id);
201         }
202         FileInputStream stateS = null;
203         ObjectInputStream stateObjS = null;
204         FileInputStream mdS = null;
205         try {
206             stateS = new FileInputStream(stateF);
207             stateObjS = new ObjectInputStream(stateS);
208             DataPackage pp = (DataPackage) stateObjS.readObject();
209             mdS = new FileInputStream(mdF);
210             Model model = ModelFactory.createDefaultModel();
211             model.read(mdS, "", "N3");
212             LOG.debug("Retrieved metadata containing " + model.size()
213                     + " statements");
214             pp.setMetadata(model);
215             return pp;
216         } catch (FileNotFoundException e) {
217             LOG.error("Unexpected problem: " + e.getMessage(), e);
218             throw new RuntimeException("Unexpected problem: " + e.getMessage(),
219                     e);
220         } catch (IOException e) {
221             LOG.error("Problem storing data: " + e.getMessage(), e);
222             throw new RuntimeException("Problem storing data: "
223                     + e.getMessage(), e);
224         } catch (ClassNotFoundException e) {
225             LOG.error("Unexpected problem: " + e.getMessage(), e);
226             throw new RuntimeException("Unexpected problem: " + e.getMessage(),
227                     e);
228         } finally {
229             if (stateS != null) {
230                 try {
231                     stateS.close();
232                 } catch (IOException e) {
233                     LOG.warn(e);
234                 }
235             }
236             if (stateObjS != null) {
237                 try {
238                     stateObjS.close();
239                 } catch (IOException e) {
240                     LOG.warn(e);
241                 }
242             }
243         }
244     }
245 
246     public File createDataFileHandle(DataPackage process) {
247         if (process.getId() == null) {
248             throw new IllegalStateException(
249                     "Cannot create file handles for processes without an id. Save the process first");
250         }
251         File pDir = new File(storageDir, process.getId());
252         if (!pDir.exists()) {
253             throw new IllegalStateException(
254                     "Cannot create file handles for a process that hasn't been saved");
255         }
256         File workDir = new File(pDir, WORK_DIR_NAME);
257         if (!workDir.exists()) {
258             throw new IllegalStateException(
259                     "Cannot create file handles for a process that hasn't been saved");
260         }
261         File f = new File(workDir, UUID.randomUUID().toString());
262         try {
263             f.createNewFile();
264         } catch (IOException e) {
265             LOG.error("Could not create file handle for data file: "
266                     + e.getMessage(), e);
267             throw new RuntimeException(
268                     "Could not create file handle for data file: "
269                             + e.getMessage(), e);
270         }
271         return f;
272     }
273 
274     public DataPackage create(Profile profile) {
275         DataPackage pp = profile.createPackage();
276         LOG.debug("Configuring data package using data files: "+ pp.getRemainingDataFiles());
277         LOG.debug("Type map contains: "+ type.keySet());
278         for (DataFile df : pp.getRemainingDataFiles()) {
279             if (df.getType() != null) {
280                 DataFileType dft = type.get(df.getType());
281                 LOG.debug("Adding a "+ dft +" data file");
282                 df.setDataFileType(dft);
283             }
284         }
285         return pp;
286     }
287 
288     public File getPackagingDirectory(String id, boolean clean) {
289         File pkgDir = new File(storageDir, id);
290         if (!pkgDir.exists()) {
291             throw new IllegalStateException(
292                     "Cannot load a package that hasn't been saved");
293         }
294         File packagingDir = new File(pkgDir, PKG_DIR_NAME);
295         if (packagingDir.exists() && clean) {
296             Util.rmr(packagingDir);
297         }
298         packagingDir.mkdirs();
299         return packagingDir;
300     }
301 
302     public File getPackagedFile(String packageId, String filename) {
303         if (packageId == null) {
304             throw new IllegalArgumentException("Package ID was null");
305         }
306         if (filename == null) {
307             throw new IllegalArgumentException("Filename was null");
308         }
309         File pkgDir = new File(storageDir, packageId);
310         File packagingDir = new File(pkgDir, PKG_DIR_NAME);
311         if (!packagingDir.exists()) {
312             throw new IllegalStateException("Package " + packageId
313                     + " has not been packaged yet, files are not available.");
314         }
315         File f = new File(packagingDir, filename);
316         if (!f.exists()) {
317             throw new RuntimeException("File: " + filename
318                     + " does not exist in package " + packageId);
319         }
320         return f;
321     }
322 
323     public File createArchiveFile(String packageId) {
324         File pkgDir = new File(storageDir, packageId);
325         String archiveFileName = packageId.hashCode() +".zip";
326         return new File(pkgDir, archiveFileName);
327     }
328 
329 }