//Prevayler(TM) - The Free-Software Prevalence Layer. //Copyright (C) 2001 Klaus Wuestefeld //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. //Contributions: Justin Sampson, Eric Bridgwater package org.prevayler.implementation; import org.prevayler.foundation.FileManager; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; public class PrevaylerDirectory { private static final int DIGITS_IN_FILENAME = 19; private static final String SNAPSHOT_SUFFIX_PATTERN = "[a-zA-Z0-9]*[Ss]napshot"; private static final String SNAPSHOT_FILENAME_PATTERN = "\\d{" + DIGITS_IN_FILENAME + "}\\." + SNAPSHOT_SUFFIX_PATTERN; private static final String JOURNAL_SUFFIX_PATTERN = "[a-zA-Z0-9]*[Jj]ournal"; private static final String JOURNAL_FILENAME_PATTERN = "\\d{" + DIGITS_IN_FILENAME + "}\\." + JOURNAL_SUFFIX_PATTERN; private File _directory; public PrevaylerDirectory(String directory) { this(new File(directory)); } public PrevaylerDirectory(File directory) { _directory = directory; } public void produceDirectory() throws IOException { FileManager.produceDirectory(_directory); } public static void checkValidSnapshotSuffix(String suffix) { if (!suffix.matches(SNAPSHOT_SUFFIX_PATTERN)) { throw new IllegalArgumentException( "Snapshot filename suffix must match /" + SNAPSHOT_SUFFIX_PATTERN + "/, but '" + suffix + "' does not"); } } public static void checkValidJournalSuffix(String suffix) { if (!suffix.matches(JOURNAL_SUFFIX_PATTERN)) { throw new IllegalArgumentException( "Journal filename suffix must match /" + JOURNAL_SUFFIX_PATTERN + "/, but '" + suffix + "' does not"); } } public File snapshotFile(long version, String suffix) { checkValidSnapshotSuffix(suffix); return file(version, suffix); } public File journalFile(long transaction, String suffix) { checkValidJournalSuffix(suffix); return file(transaction, suffix); } private File file(long version, String suffix) { String fileName = "0000000000000000000" + version; return new File(_directory, fileName.substring(fileName.length() - DIGITS_IN_FILENAME) + "." + suffix); } /** * Returns -1 if fileName is not the name of a snapshot file. */ public static long snapshotVersion(File file) { return version(file, SNAPSHOT_FILENAME_PATTERN); } /** * Returns -1 if fileName is not the name of a journal file. */ public static long journalVersion(File file) { return version(file, JOURNAL_FILENAME_PATTERN); } private static long version(File file, String filenamePattern) { String fileName = file.getName(); if (!fileName.matches(filenamePattern)) return -1; return Long.parseLong(fileName.substring(0, fileName.indexOf("."))); } /** * Find the latest snapshot file. Returns null if no snapshot file was found. */ public File latestSnapshot() throws IOException { File[] files = _directory.listFiles(); if (files == null) throw new IOException("Error reading file list from directory " + _directory); File latestSnapshot = null; long latestVersion = 0; for (int i = 0; i < files.length; i++) { File candidateSnapshot = files[i]; long candidateVersion = snapshotVersion(candidateSnapshot); if (candidateVersion > latestVersion) { latestVersion = candidateVersion; latestSnapshot = candidateSnapshot; } } return latestSnapshot; } public File findInitialJournalFile(long initialTransactionWanted) { File[] journals = _directory.listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.getName().matches(JOURNAL_FILENAME_PATTERN); } }); Arrays.sort(journals, new Comparator() { public int compare(Object o1, Object o2) { File f1 = (File) o1; File f2 = (File) o2; return new Long(journalVersion(f1)).compareTo(new Long(journalVersion(f2))); } }); for (int i = journals.length - 1; i >= 0; i--) { File journal = journals[i]; long version = journalVersion(journal); if (version <= initialTransactionWanted) { return journal; } } return null; } public File createTempFile(String prefix, String suffix) throws IOException { return File.createTempFile(prefix, suffix, _directory); } public static void renameUnusedFile(File journalFile) { journalFile.renameTo(new File(journalFile.getAbsolutePath() + ".unusedFile" + System.currentTimeMillis())); } }