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
43
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
133 stateF.createNewFile();
134 stateOutS = new FileOutputStream(stateF);
135 stateObjOutS = new ObjectOutputStream(stateOutS);
136 stateObjOutS.writeObject(pkg);
137
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 }