Source code: marf/Storage/StorageManager.java
1 package marf.Storage;
2
3 import java.io.FileInputStream;
4 import java.io.FileNotFoundException;
5 import java.io.FileOutputStream;
6 import java.io.ObjectInputStream;
7 import java.io.ObjectOutputStream;
8 import java.util.zip.GZIPInputStream;
9 import java.util.zip.GZIPOutputStream;
10
11 import marf.util.NotImplementedException;
12
13
14 /**
15 * <p>Class StorageManager.</p>
16 * <p>Almost every concrete module must inherit from this class.
17 * If that's not possible, implement IStorageManager interface.</p>
18 *
19 * <p>$Id: StorageManager.java,v 1.23 2005/06/20 21:45:15 mokhov Exp $</p>
20 *
21 * @author Serguei Mokhov
22 * @version $Revision: 1.23 $
23 * @since 0.0.1
24 */
25 public abstract class StorageManager
26 implements IStorageManager
27 {
28 /**
29 * Indicates in which format dump training data.
30 * <p>Can either be one of the <code>DUMP_</code> flags,
31 * with the <code>DUMP_GZIP_BINARY</code> being the default.</p>
32 *
33 * @since 0.2.0
34 */
35 protected transient int iCurrentDumpMode = DUMP_GZIP_BINARY;
36
37 /**
38 * Filename of the file to be dumped/restored.
39 * @since 0.3.0
40 */
41 protected transient String strFilename = null;
42
43 /**
44 * Actual object to be serialized (primarily for GZIP and BINARY modes.
45 * Has to be back-synchronized.
46 * @since 0.3.0
47 * @see #backSynchronizeObject()
48 */
49 protected Object oObjectToSerialize = null;
50
51 /**
52 * If set to <code>true</code> (the default), causes
53 * <code>restoreBinary()</code> or <code>restoreGzipBinary()</code>
54 * to create a file if it does not exist. If set to <code>false<code>,
55 * an exception is thrown.
56 *
57 * @since 0.3.0
58 *
59 * @see #restoreBinary()
60 * @see #restoreGzipBinary()
61 */
62 protected transient boolean bDumpOnNotFound = true;
63
64 /**
65 * Default constructor equivalent to <code>StorageManager(null, getClass().getName())</code>.
66 * Sets internal filename to the class name of the derivative.
67 * @since 0.3.0
68 * @see #StorageManager(Object, String)
69 * @see #strFilename
70 */
71 public StorageManager()
72 {
73 /*
74 * We cannot call getClass().getName() in
75 * this() because 'this' has to exist first.
76 */
77 this(null, "");
78 setFilename(getClass().getName());
79 }
80
81 /**
82 * Constructor with filename parameter equivalent to
83 * <code>StorageManager(null, pstrFilename)</code>.
84 * @param pstrFilename customized filename
85 * @since 0.3.0
86 * @see #StorageManager(Object, String)
87 * @see #strFilename
88 */
89 public StorageManager(String pstrFilename)
90 {
91 this(null, pstrFilename);
92 }
93
94 /**
95 * General constructor with serializable object parameter.
96 * Sets internal filename to the class name of the parameter.
97 * @param poObjectToSerialize reference to object to be dumped to a file
98 * @since 0.3.0
99 * @see #oObjectToSerialize
100 * @see #bDumpOnNotFound
101 */
102 public StorageManager(Object poObjectToSerialize)
103 {
104 this(poObjectToSerialize, poObjectToSerialize.getClass().getName());
105 }
106
107 /**
108 * General constructor with filename and serializable object parameters.
109 * @param poObjectToSerialize reference to object to be dumped to a file
110 * @param pstrFilename customized filename
111 * @since 0.3.0
112 * @see #oObjectToSerialize
113 * @see #strFilename
114 * @see #bDumpOnNotFound
115 */
116 public StorageManager(Object poObjectToSerialize, String pstrFilename)
117 {
118 this.strFilename = pstrFilename;
119 this.oObjectToSerialize = poObjectToSerialize;
120 }
121
122 /**
123 * Constructor with filename parameter equivalent to
124 * <code>StorageManager(null, pstrFilename)</code>.
125 * @param pstrFilename customized filename
126 * @param pbDumpOnNotFound if <code>true</code>, a dump file will be created if it does not exist;
127 * if <code>false</code>, an exception will be thrown
128 * @since 0.3.0
129 * @see #StorageManager(Object, String)
130 * @see #strFilename
131 */
132 public StorageManager(String pstrFilename, boolean pbDumpOnNotFound)
133 {
134 this(null, pstrFilename, pbDumpOnNotFound);
135 }
136
137 /**
138 * General constructor with serializable object parameter.
139 * Sets internal filename to the class name of the parameter.
140 * @param poObjectToSerialize reference to object to be dumped to a file
141 * @param pbDumpOnNotFound if <code>true</code>, a dump file will be created if it does not exist;
142 * if <code>false</code>, an exception will be thrown
143 * @since 0.3.0
144 * @see #oObjectToSerialize
145 * @see #bDumpOnNotFound
146 */
147 public StorageManager(Object poObjectToSerialize, boolean pbDumpOnNotFound)
148 {
149 this(poObjectToSerialize, poObjectToSerialize.getClass().getName(), pbDumpOnNotFound);
150 }
151
152 /**
153 * General constructor with filename and serializable object parameters.
154 * @param poObjectToSerialize reference to object to be dumped to a file
155 * @param pstrFilename customized filename
156 * @param pbDumpOnNotFound if <code>true</code>, a dump file will be created if it does not exist;
157 * if <code>false</code>, an exception will be thrown
158 * @since 0.3.0
159 * @see #oObjectToSerialize
160 * @see #strFilename
161 */
162 public StorageManager(Object poObjectToSerialize, String pstrFilename, boolean pbDumpOnNotFound)
163 {
164 this.strFilename = pstrFilename;
165 this.oObjectToSerialize = poObjectToSerialize;
166 this.bDumpOnNotFound = pbDumpOnNotFound;
167 }
168
169 /**
170 * An object must know how dump itself or its data structures to a file.
171 * Options are: Object serialization, XML, CSV, HTML, SQL. Internally, the method
172 * calls all the <code>dump*()</code> methods based on the current dump mode.
173 * If the derivatives use only <code>DUMP_GZIP_BINARY</code> or <code>DUMP_BINARY</code> modes, the
174 * need not do anything except implementing <code>backSynchronizeObject()</code>. For the
175 * rest of modes they only have to override a corresponding <code>dump*()</code> method.
176 *
177 * @throws StorageException if saving to a file for some reason fails or
178 * the dump mode set to an unsupported value
179 *
180 * @see #DUMP_GZIP_BINARY
181 * @see #DUMP_BINARY
182 * @see #dumpGzipBinary()
183 * @see #dumpCSV()
184 * @see #dumpBinary()
185 * @see #dumpXML()
186 * @see #dumpHTML()
187 * @see #dumpSQL()
188 * @see #backSynchronizeObject()
189 * @see #iCurrentDumpMode
190 */
191 public synchronized void dump()
192 throws StorageException
193 {
194 switch(this.iCurrentDumpMode)
195 {
196 case DUMP_GZIP_BINARY:
197 dumpGzipBinary();
198 break;
199
200 case DUMP_CSV_TEXT:
201 dumpCSV();
202 break;
203
204 case DUMP_BINARY:
205 dumpBinary();
206 break;
207
208 case DUMP_XML:
209 dumpXML();
210 break;
211
212 case DUMP_HTML:
213 dumpHTML();
214 break;
215
216 case DUMP_SQL:
217 dumpSQL();
218 break;
219
220 default:
221 throw new StorageException("Unsupported dump mode: " + this.iCurrentDumpMode);
222 }
223 }
224
225 /**
226 * Implements object dump in GZIP-compressed form. Attempts
227 * to save internal object reference to the generater/specified filename
228 * @throws StorageException in case of I/O or otherwise error during object dump
229 * @since 0.3.0
230 * @see #oObjectToSerialize
231 * @see #strFilename
232 */
233 public synchronized void dumpGzipBinary()
234 throws StorageException
235 {
236 try
237 {
238 FileOutputStream oFOS = new FileOutputStream(strFilename);
239 GZIPOutputStream oGZOS = new GZIPOutputStream(oFOS);
240 ObjectOutputStream oOOS = new ObjectOutputStream(oGZOS);
241
242 oOOS.writeObject(this.oObjectToSerialize);
243 oOOS.flush();
244 oOOS.close();
245 }
246 catch(Exception e)
247 {
248 throw new StorageException(e);
249 }
250 }
251
252 /**
253 * Implements object dump in plain binary form without compression. Attempts
254 * to save internal object reference to the generater/specified filename
255 * @throws StorageException in case of I/O or otherwise error during object dump
256 * @since 0.3.0
257 * @see #oObjectToSerialize
258 * @see #strFilename
259 */
260 public synchronized void dumpBinary()
261 throws StorageException
262 {
263 try
264 {
265 FileOutputStream oFOS = new FileOutputStream(this.strFilename);
266 ObjectOutputStream oOOS = new ObjectOutputStream(oFOS);
267
268 oOOS.writeObject(this.oObjectToSerialize);
269 oOOS.flush();
270 oOOS.close();
271 }
272 catch(Exception e)
273 {
274 throw new StorageException(e);
275 }
276 }
277
278 /**
279 * If derivatives use the generic implementation of <code>dump()</code>
280 * with the CSV dump mode, they must override this method.
281 * @throws NotImplementedException
282 * @throws StorageException, declared, but never thrown
283 * @since 0.3.0
284 * @see #dump()
285 */
286 public synchronized void dumpCSV()
287 throws StorageException
288 {
289 throw new NotImplementedException(this, "dumpCSV()");
290 }
291
292 /**
293 * If derivatives use the generic implementation of <code>dump()</code>
294 * with the XML dump mode, they must override this method.
295 * @throws NotImplementedException
296 * @throws StorageException, declared, but never thrown
297 * @since 0.3.0
298 * @see #dump()
299 */
300 public synchronized void dumpXML()
301 throws StorageException
302 {
303 throw new NotImplementedException(this, "dumpXML()");
304 }
305
306 /**
307 * If derivatives use the generic implementation of <code>dump()</code>
308 * with the HTML dump mode, they must override this method.
309 * @throws NotImplementedException
310 * @throws StorageException, declared, but never thrown
311 * @since 0.3.0
312 * @see #dump()
313 */
314 public synchronized void dumpHTML()
315 throws StorageException
316 {
317 throw new NotImplementedException(this, "dumpHTML()");
318 }
319
320 /**
321 * If derivatives use the generic implementation of <code>dump()</code>
322 * with the SQL dump mode, they must override this method.
323 * @throws NotImplementedException
324 * @throws StorageException, declared, but never thrown
325 * @since 0.3.0
326 * @see #dump()
327 */
328 public synchronized void dumpSQL()
329 throws StorageException
330 {
331 throw new NotImplementedException(this, "dumpSQL()");
332 }
333
334 /**
335 * An object must know how restore itself or its data structures from a file.
336 * Options are: Object serialization, XML, CSV, HTML, SQL. Internally, the method
337 * calls all the <code>restore*()</code> methods based on the current dump mode.
338 * If the derivatives use only <code>DUMP_GZIP_BINARY</code> or <code>DUMP_BINARY</code> modes, the
339 * need not do anything except implementing <code>backSynchronizeObject()</code>. For the
340 * rest of modes they only have to override a corresponding <code>restore*()</code> method.
341 *
342 * @throws StorageException if loading from a file for some reason fails or
343 * the dump mode set to an unsupported value
344 *
345 * @see #DUMP_GZIP_BINARY
346 * @see #DUMP_BINARY
347 * @see #dumpGzipBinary()
348 * @see #dumpCSV()
349 * @see #dumpBinary()
350 * @see #dumpXML()
351 * @see #dumpHTML()
352 * @see #dumpSQL()
353 * @see #backSynchronizeObject()
354 * @see #iCurrentDumpMode
355 */
356 public synchronized void restore()
357 throws StorageException
358 {
359 switch(this.iCurrentDumpMode)
360 {
361 case DUMP_GZIP_BINARY:
362 restoreGzipBinary();
363 break;
364
365 case DUMP_CSV_TEXT:
366 restoreCSV();
367 break;
368
369 case DUMP_BINARY:
370 restoreBinary();
371 break;
372
373 case DUMP_XML:
374 restoreXML();
375 break;
376
377 case DUMP_HTML:
378 restoreHTML();
379 break;
380
381 case DUMP_SQL:
382 restoreSQL();
383 break;
384
385 default:
386 throw new StorageException("Unsupported dump mode: " + this.iCurrentDumpMode);
387 }
388 }
389
390 /**
391 * Implements object loading from plain binary form without compression. Attempts
392 * to load internal object reference with the generater/specified filename. After,
393 * calls <code>backSynchronizeObject()</code> so the actual mode can reset back
394 * references in its own data structures. If the file that we attempt to load
395 * did not exist, it will be created.
396 *
397 * @throws StorageException in case of I/O or otherwise error during object retoration
398 * @since 0.3.0
399 * @see #backSynchronizeObject()
400 * @see #strFilename
401 */
402 public synchronized void restoreBinary()
403 throws StorageException
404 {
405 try
406 {
407 FileInputStream oFIS = new FileInputStream(strFilename);
408 ObjectInputStream oOIS = new ObjectInputStream(oFIS);
409
410 this.oObjectToSerialize = oOIS.readObject();
411
412 oOIS.close();
413
414 backSynchronizeObject();
415 }
416 catch(FileNotFoundException e)
417 {
418 if(this.bDumpOnNotFound == true)
419 {
420 System.err.println
421 (
422 "StorageManager.restore() --- FileNotFoundException for file: \""
423 + strFilename + "\", " +
424 e.getMessage() + "\n" +
425 "Creating one now..."
426 );
427
428 dump();
429 }
430 else
431 {
432 throw new StorageException(e);
433 }
434 }
435 catch(ClassNotFoundException e)
436 {
437 throw new StorageException
438 (
439 "StorageManager.restore() --- ClassNotFoundException: " +
440 e.getMessage()
441 );
442 }
443 catch(Exception e)
444 {
445 throw new StorageException(e);
446 }
447 }
448
449 /**
450 * Implements object loading from GZIP-compressed binary form. Attempts
451 * to load internal object reference with the generater/specified filename. After,
452 * calls <code>backSynchronizeObject()</code> so the actual mode can reset back
453 * references in its own data structures. If the file that we attempt to load
454 * did not exist, it will be created.
455 *
456 * @throws StorageException in case of I/O or otherwise error during object retoration
457 * @since 0.3.0
458 * @see #backSynchronizeObject()
459 * @see #strFilename
460 */
461 public synchronized void restoreGzipBinary()
462 throws StorageException
463 {
464 try
465 {
466 FileInputStream oFIS = new FileInputStream(this.strFilename);
467 GZIPInputStream oGZIS = new GZIPInputStream(oFIS);
468 ObjectInputStream oOIS = new ObjectInputStream(oGZIS);
469
470 this.oObjectToSerialize = oOIS.readObject();
471
472 oOIS.close();
473
474 backSynchronizeObject();
475 }
476 catch(FileNotFoundException e)
477 {
478 if(this.bDumpOnNotFound == true)
479 {
480 System.err.println
481 (
482 "StorageManager.restore() --- FileNotFoundException for file: \""
483 + this.strFilename + "\", " +
484 e.getMessage() + "\n" +
485 "Creating one now..."
486 );
487
488 dump();
489 }
490 else
491 {
492 throw new StorageException(e);
493 }
494 }
495 catch(ClassNotFoundException e)
496 {
497 throw new StorageException
498 (
499 "StorageManager.restore() --- ClassNotFoundException: " +
500 e.getMessage()
501 );
502 }
503 catch(Exception e)
504 {
505 throw new StorageException(e);
506 }
507 }
508
509 /**
510 * If derivatives use the generic implementation of <code>restore()</code>
511 * with the CSV dump mode, they must override this method.
512 * @throws NotImplementedException
513 * @throws StorageException, declared, but never thrown
514 * @since 0.3.0
515 * @see #restore()
516 */
517 public synchronized void restoreCSV()
518 throws StorageException
519 {
520 throw new NotImplementedException(this, "restoreCSV()");
521 }
522
523 /**
524 * If derivatives use the generic implementation of <code>restore()</code>
525 * with the XML dump mode, they must override this method.
526 * @throws NotImplementedException
527 * @throws StorageException, declared, but never thrown
528 * @since 0.3.0
529 * @see #restore()
530 */
531 public synchronized void restoreXML()
532 throws StorageException
533 {
534 throw new NotImplementedException(this, "restoreXML()");
535 }
536
537 /**
538 * If derivatives use the generic implementation of <code>restore()</code>
539 * with the HTML dump mode, they must override this method.
540 * @throws NotImplementedException
541 * @throws StorageException, declared, but never thrown
542 * @since 0.3.0
543 * @see #restore()
544 */
545 public synchronized void restoreHTML()
546 throws StorageException
547 {
548 throw new NotImplementedException(this, "restoreHTML()");
549 }
550
551 /**
552 * If derivatives use the generic implementation of <code>restore()</code>
553 * with the SQL dump mode, they must override this method.
554 * @throws NotImplementedException
555 * @throws StorageException, declared, but never thrown
556 * @since 0.3.0
557 * @see #restore()
558 */
559 public synchronized void restoreSQL()
560 throws StorageException
561 {
562 throw new NotImplementedException(this, "restoreSQL()");
563 }
564
565 /**
566 * Must to be overridden by the modules that use object serialization
567 * with the generic implementation of <code>restore()</code>. By default
568 * this method is unimplemented.
569 * @throws NotImplementedException
570 * @since 0.3.0
571 * @see #restore()
572 */
573 public synchronized void backSynchronizeObject()
574 {
575 throw new NotImplementedException(this, "backSynchronizeObject()");
576 }
577
578 /**
579 * Retrieves inner filename reference.
580 * @return filename string
581 * @since 0.3.0
582 */
583 public synchronized String getFilename()
584 {
585 return this.strFilename;
586 }
587
588 /**
589 * Allows to alter inner filename reference.
590 * @param pstrFilename new filename
591 * @since 0.3.0
592 */
593 public synchronized void setFilename(String pstrFilename)
594 {
595 this.strFilename = pstrFilename;
596 }
597
598 /**
599 * Retrieves default filename extension of this storage manager.
600 * @return extension String
601 * @since 0.3.0
602 */
603 public synchronized String getDefaultExtension()
604 {
605 return getDefaultExtension(this.iCurrentDumpMode);
606 }
607
608 /**
609 * Retrieves default filename extension depending on dump type.
610 * @param piDumpMode dump mode to query extensions map by
611 * @return extension String; "unknown" is returned if the parameter
612 * is outside of the range
613 * @since 0.3.0
614 */
615 public static String getDefaultExtension(int piDumpMode)
616 {
617 try
618 {
619 return STORAGE_FILE_EXTENSIONS[piDumpMode];
620 }
621 catch(ArrayIndexOutOfBoundsException e)
622 {
623 return "unknown";
624 }
625 }
626
627 /**
628 * Retrieves current dump mode.
629 * @return the mode, integer
630 * @since 0.3.0
631 */
632 public synchronized final int getDumpMode()
633 {
634 return this.iCurrentDumpMode;
635 }
636
637 /**
638 * Sets the dump mode.
639 * @param piCurrentDumpMode the mode
640 * @since 0.3.0
641 */
642 public synchronized final void setDumpMode(final int piCurrentDumpMode)
643 {
644 this.iCurrentDumpMode = piCurrentDumpMode;
645 }
646
647 /**
648 * Enables or disables creation of a file if it does not exist.
649 * @param pbEnable new value of the flag
650 * @return old value of the flag
651 * @since 0.3.0
652 * @see #bDumpOnNotFound
653 */
654 public synchronized final boolean enableDumpOnNotFound(boolean pbEnable)
655 {
656 boolean bOld = this.bDumpOnNotFound;
657 this.bDumpOnNotFound = pbEnable;
658 return bOld;
659 }
660
661 /**
662 * Returns source code revision information.
663 * @return revision string
664 * @since 0.3.0
665 */
666 public static String getMARFSourceCodeRevision()
667 {
668 return "$Revision: 1.23 $";
669 }
670 }
671
672 // EOF