001: // Prevayler(TM) - The Open-Source Prevalence Layer.
002: // Copyright (C) 2001 Klaus Wuestefeld.
003: // This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
004:
005: package org.prevayler.implementation;
006:
007: import java.io.EOFException;
008: import java.io.File;
009: import java.io.FileFilter;
010: import java.io.IOException;
011: import java.util.Arrays;
012:
013: /** Finds the last .snapshot file by number and finds all the subsequent pending .log files.
014: */
015: class NumberFileFinder {
016:
017: private File directory;
018: private File lastSnapshot;
019: private long fileNumber;
020: private NumberFileCreator fileCreator;
021:
022: /** @throws IOException if location does not exist and cannot be created as a directory.
023: * @throws IllegalArgumentException If location exists and is not a directory.
024: */
025: public NumberFileFinder(String directoryName) throws IOException {
026: this .directory = new File(directoryName);
027: if (!directory.exists() && !directory.mkdirs())
028: throw new IOException(
029: "Directory doesn't exist and could not be created: "
030: + directoryName);
031: if (!directory.isDirectory())
032: throw new IllegalArgumentException(
033: "Path exists but is not a directory: "
034: + directoryName);
035:
036: System.out.println("Directory for Prevayler is: "
037: + directory.getAbsolutePath());
038:
039: init();
040: }
041:
042: /** Returns the last snapshot file. Returns null if there are no snapshots.
043: */
044: public File lastSnapshot() {
045: return lastSnapshot;
046: }
047:
048: /** @throws EOFException if there are no more pending .log files.
049: */
050: public File nextPendingLog() throws EOFException {
051: File log = new File(directory, NumberFileCreator.LOG_FORMAT
052: .format(fileNumber + 1));
053: if (!log.exists()) {
054: fileCreator = new NumberFileCreator(directory,
055: fileNumber + 1);
056: throw new EOFException();
057: }
058: ++fileNumber;
059: return log;
060: }
061:
062: /** Returns a NumberFileCreator that will start off with the first number after the last .log file number.
063: * @return null if there are still .log files pending.
064: */
065: public NumberFileCreator fileCreator() {
066: return fileCreator;
067: }
068:
069: private void init() throws IOException {
070: findLastSnapshot();
071: fileNumber = lastSnapshot == null ? 0 : number(lastSnapshot);
072: }
073:
074: private long number(File snapshot) throws NumberFormatException { //NumberFomatException is a RuntimeException.
075: String name = snapshot.getName();
076: if (!name.endsWith("." + NumberFileCreator.SNAPSHOT_SUFFIX))
077: throw new NumberFormatException();
078: return Long.parseLong(name.substring(0, name.indexOf('.'))); // "00000.snapshot" becomes "00000".
079: //The following doesn't work! It throws ParseException (UnparseableNumber): return (NumberFileCreator.SNAPSHOT_FORMAT.parse(snapshot.getName())).longValue();
080: }
081:
082: private void findLastSnapshot() throws IOException {
083: File[] snapshots = directory.listFiles(new SnapshotFilter());
084: if (snapshots == null)
085: throw new IOException(
086: "Error reading file list from directory "
087: + directory);
088:
089: Arrays.sort(snapshots);
090:
091: lastSnapshot = snapshots.length > 0 ? snapshots[snapshots.length - 1]
092: : null;
093: }
094:
095: private class SnapshotFilter implements FileFilter {
096:
097: public boolean accept(File file) {
098: try {
099: number(file);
100: } catch (NumberFormatException nfx) {
101: return false;
102: }
103: return true;
104: }
105: }
106:
107: }
|