1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package mnemosyne.archiver;
17
18 import mnemosyne.util.Util;
19 import mnemosyne.util.PersistenceRuntimeException;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23 import java.io.*;
24 import java.text.DecimalFormat;
25 import java.util.SortedSet;
26 import java.util.TreeSet;
27
28 /***
29 * @version $Id: ArchiveDirectory.java,v 1.1.1.1 2004/08/07 06:40:49 charlesblaxland Exp $
30 */
31 public abstract class ArchiveDirectory
32 {
33 private static final Log log = LogFactory.getLog(ArchiveDirectory.class);
34
35 private static final String IN_PROGRESS_SUFFIX = "_";
36 private static final String SEQUENCE_FORMAT = "0000000000000000000";
37 private static final DecimalFormat sequenceFormatter = new DecimalFormat(SEQUENCE_FORMAT);
38
39 private File directory;
40 protected SortedSet archiveFiles;
41 private ArchiveSequence sequence;
42
43 protected ArchiveDirectory(String directoryName, ArchiveSequence sequence)
44 {
45 if (!Util.ensureDirectoryExists(directoryName))
46 {
47 throw new PersistenceRuntimeException("Unable to create archive directory");
48 }
49 this.directory = new File(directoryName);
50 this.sequence = sequence;
51 scanDirectory();
52 }
53
54 protected abstract String prefix();
55 protected abstract String postfix();
56 protected abstract String extension();
57
58 protected ObjectOutputStream createOutputStream(OutputStream output) throws IOException
59 {
60 return new ArchiveOutputStream(output);
61 }
62
63 protected ObjectInputStream createInputStream(InputStream input) throws IOException
64 {
65 return new ArchiveInputStream(input);
66 }
67
68 private void scanDirectory()
69 {
70 log.debug("Scanning archive directory " + directory.getPath());
71 File[] files = directory.listFiles(new FilenameFilter() {
72 public boolean accept(File dir, String name)
73 {
74 return isValidArchiveFile(name);
75 }
76 });
77
78 initializeFileCollection(files);
79 }
80
81 protected boolean isValidArchiveFile(String filename)
82 {
83 boolean isValid =
84 filename.startsWith(prefix()) &&
85 filename.endsWith(postfix() + "." + extension()) &&
86 filename.length() == prefix().length() + SEQUENCE_FORMAT.length() + postfix().length() + ".".length() + extension().length();
87
88 return isValid;
89 }
90
91 private void initializeFileCollection(File[] files)
92 {
93 archiveFiles = new TreeSet();
94 long maxSequenceNumber = -1;
95 for (int i = 0; i < files.length; i++)
96 {
97 File file = files[i];
98 try
99 {
100 long sequenceNumber = extractFileSequenceNumber(file.getName());
101 log.debug("Found archive file " + file.getName());
102 if (sequenceNumber > maxSequenceNumber)
103 {
104 maxSequenceNumber = sequenceNumber;
105 }
106 archiveFiles.add(files[i].getName());
107 }
108 catch (NumberFormatException e)
109 {
110 log.debug("Invalid archive file found in archive directory: " + file.getName());
111 }
112 }
113
114 sequence.advanceValue(maxSequenceNumber + 1);
115 }
116
117 protected boolean isEmpty()
118 {
119 return archiveFiles.isEmpty();
120 }
121
122 protected long extractFileSequenceNumber(String filename) throws NumberFormatException
123 {
124 int startSequenceIndex = prefix().length();
125 int finishSequenceIndex = filename.indexOf(".") - postfix().length();
126 String sequenceNumber = filename.substring(startSequenceIndex, finishSequenceIndex);
127 long retval = Long.parseLong(sequenceNumber);
128 log.debug("Extracted sequence " + retval + " from filename " + filename);
129 return retval;
130 }
131
132 protected File allocateNewInProgressArchiveFile()
133 {
134 return new File(directory, buildArchiveFilename(sequence.getNext()) + IN_PROGRESS_SUFFIX);
135 }
136
137 protected File constructArchiveFile(String archiveFilename)
138 {
139 return new File(directory, archiveFilename);
140 }
141
142 protected String buildArchiveFilename(long sequenceNumber)
143 {
144 return prefix() + sequenceFormatter.format(sequenceNumber) + postfix() + "." + extension();
145 }
146
147 protected Object readArchiveFile(File archiveFile) throws ArchiverException
148 {
149 if (log.isDebugEnabled())
150 log.debug("Loading file " + archiveFile.getPath());
151
152 FileInputStream fileInput = null;
153 ObjectInputStream input = null;
154 Object retval = null;
155 try
156 {
157 fileInput = new FileInputStream(archiveFile);
158 input = createInputStream(new BufferedInputStream(fileInput));
159 retval = input.readObject();
160 }
161 catch (ClassNotFoundException e)
162 {
163 throw new ArchiverException("Exception occurred while trying to load archive " + archiveFile.getPath(), e);
164 }
165 catch (IOException e)
166 {
167 throw new ArchiverException("Exception occurred while trying to load archive" + archiveFile.getPath(), e);
168 }
169 finally
170 {
171 try
172 {
173 if (input != null)
174 {
175 input.close();
176 }
177 else if (fileInput != null)
178 {
179 fileInput.close();
180 }
181 }
182 catch (IOException e)
183 {
184 log.warn("Unable to close archive file " + archiveFile.getPath());
185 }
186 }
187 return retval;
188 }
189
190 public void writeArchiveFile(Object obj) throws ArchiverException
191 {
192 File outputFile = allocateNewInProgressArchiveFile();
193 if (log.isDebugEnabled())
194 log.debug("Writing archive to " + outputFile.getPath());
195
196 boolean removeOutputFile = false;
197 FileOutputStream fileOutput = null;
198 ObjectOutputStream output = null;
199 try
200 {
201 fileOutput = new FileOutputStream(outputFile);
202 output = createOutputStream(new BufferedOutputStream(fileOutput));
203 output.writeObject(obj);
204 }
205 catch (IOException e)
206 {
207 removeOutputFile = true;
208 throw new ArchiverException("Exception occurred while trying to save archive", e);
209 }
210 finally
211 {
212 try
213 {
214 if (output != null)
215 {
216 output.flush();
217 output.close();
218 }
219 else if (fileOutput != null)
220 {
221 fileOutput.flush();
222 fileOutput.close();
223 }
224 }
225 catch (IOException e)
226 {
227 log.warn("Unable to close archive file " + outputFile.getPath(), e);
228 }
229
230 if (removeOutputFile && outputFile.exists())
231 {
232 outputFile.delete();
233 }
234 }
235
236 onArchiveComplete(outputFile);
237 }
238
239 protected void onArchiveComplete(File inProgressFile) throws ArchiverException
240 {
241 String inProgressPath = inProgressFile.getPath();
242 String completeFileName = inProgressPath.substring(0, inProgressPath.length() - IN_PROGRESS_SUFFIX.length());
243 File completeFile = new File(completeFileName);
244 if (log.isDebugEnabled())
245 log.debug("Renaming in progress archive file from " + inProgressPath + " to " + completeFile.getPath());
246 if (!inProgressFile.renameTo(completeFile))
247 {
248 throw new ArchiverException("Unable to rename in progress archive file");
249 }
250
251 archiveFiles.add(completeFile.getName());
252 }
253
254 }