1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.archive.io;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.ObjectInputStream;
31 import java.util.Iterator;
32 import java.util.LinkedList;
33
34 import org.archive.util.FileUtils;
35
36
37 /***
38 * Enhanced ObjectOutputStream with support for restoring
39 * files that had been saved, in parallel with object
40 * serialization.
41 *
42 * @author gojomo
43 *
44 */
45 public class ObjectPlusFilesInputStream extends ObjectInputStream {
46 LinkedList<File> auxiliaryDirectoryStack = new LinkedList<File>();
47 LinkedList<Runnable> postRestoreTasks = new LinkedList<Runnable>();
48
49 /***
50 * Instantiate over the given stream and using the supplied
51 * auxiliary storage directory.
52 *
53 * @param in
54 * @param storeDir
55 * @throws IOException
56 */
57 public ObjectPlusFilesInputStream(InputStream in, File storeDir)
58 throws IOException {
59 super(in);
60 auxiliaryDirectoryStack.addFirst(storeDir);
61 }
62
63 /***
64 * Push another default storage directory for use
65 * until popped.
66 *
67 * @param dir
68 */
69 public void pushAuxiliaryDirectory(String dir) {
70 auxiliaryDirectoryStack.
71 addFirst(new File(getAuxiliaryDirectory(), dir));
72 }
73
74 /***
75 * Discard the top auxiliary directory.
76 */
77 public void popAuxiliaryDirectory() {
78 auxiliaryDirectoryStack.removeFirst();
79 }
80
81 /***
82 * Return the top auxiliary directory, from
83 * which saved files are restored.
84 *
85 * @return Auxillary directory.
86 */
87 public File getAuxiliaryDirectory() {
88 return (File)auxiliaryDirectoryStack.getFirst();
89 }
90
91 /***
92 * Restore a file from storage, using the name and length
93 * info on the serialization stream and the file from the
94 * current auxiliary directory, to the given File.
95 *
96 * @param destination
97 * @throws IOException
98 */
99 public void restoreFile(File destination) throws IOException {
100 String nameAsStored = readUTF();
101 long lengthAtStoreTime = readLong();
102 File storedFile = new File(getAuxiliaryDirectory(),nameAsStored);
103 FileUtils.copyFile(storedFile, destination, lengthAtStoreTime);
104 }
105
106 /***
107 * Restore a file from storage, using the name and length
108 * info on the serialization stream and the file from the
109 * current auxiliary directory, to the given File.
110 *
111 * @param directory
112 * @throws IOException
113 */
114 public void restoreFileTo(File directory) throws IOException {
115 String nameAsStored = readUTF();
116 long lengthAtStoreTime = readLong();
117 File storedFile = new File(getAuxiliaryDirectory(),nameAsStored);
118 File destination = new File(directory,nameAsStored);
119 FileUtils.copyFile(storedFile, destination, lengthAtStoreTime);
120 }
121
122 /***
123 * Register a task to be done when the ObjectPlusFilesInputStream
124 * is closed.
125 *
126 * @param task
127 */
128 public void registerFinishTask(Runnable task) {
129 postRestoreTasks.addFirst(task);
130 }
131
132 private void doFinishTasks() {
133 Iterator iter = postRestoreTasks.iterator();
134 while(iter.hasNext()) {
135 ((Runnable)iter.next()).run();
136 }
137 }
138
139 /***
140 * In addition to default, do any registered cleanup tasks.
141 *
142 * @see java.io.InputStream#close()
143 */
144 public void close() throws IOException {
145 super.close();
146 doFinishTasks();
147 }
148 }