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()));
}
}