/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal.fileheader; import com.db4o.*; import com.db4o.ext.*; import com.db4o.internal.*; /** * @exclude */ public abstract class FileHeader { public static final int TRANSACTION_POINTER_LENGTH = Const4.INT_LENGTH * 2; private static final FileHeader[] AVAILABLE_FILE_HEADERS = new FileHeader[]{ new FileHeader1(), new FileHeader2(), new FileHeader3(), }; public static NewFileHeaderBase newCurrentFileHeader(){ return new FileHeader3(); } private static int readerLength(){ int length = AVAILABLE_FILE_HEADERS[0].length(); for (int i = 1; i < AVAILABLE_FILE_HEADERS.length; i++) { length = Math.max(length, AVAILABLE_FILE_HEADERS[i].length()); } return length; } public static FileHeader read(LocalObjectContainer file) throws OldFormatException { ByteArrayBuffer reader = prepareFileHeaderReader(file); FileHeader header = detectFileHeader(file, reader); if(header == null){ Exceptions4.throwRuntimeException(Messages.INCOMPATIBLE_FORMAT, file.toString()); } else { header.read(file, reader); } return header; } public FileHeader convert(LocalObjectContainer file){ FileHeader3 fileHeader = new FileHeader3(); fileHeader.initNew(file); return fileHeader; } private static ByteArrayBuffer prepareFileHeaderReader(LocalObjectContainer file) { ByteArrayBuffer reader = new ByteArrayBuffer(readerLength()); reader.read(file, 0, 0); return reader; } private static FileHeader detectFileHeader(LocalObjectContainer file, ByteArrayBuffer reader) { for (int i = 0; i < AVAILABLE_FILE_HEADERS.length; i++) { reader.seek(0); FileHeader result = AVAILABLE_FILE_HEADERS[i].newOnSignatureMatch(file, reader); if(result != null) { return result; } } return null; } public abstract void close() throws Db4oIOException; public abstract void initNew(LocalObjectContainer file) throws Db4oIOException; public abstract void completeInterruptedTransaction(LocalObjectContainer container); public abstract int length(); protected abstract FileHeader newOnSignatureMatch(LocalObjectContainer file, ByteArrayBuffer reader); protected long timeToWrite(long time, boolean shuttingDown) { return shuttingDown ? 0 : time; } protected abstract void read(LocalObjectContainer file, ByteArrayBuffer reader); protected boolean signatureMatches(ByteArrayBuffer reader, byte[] signature, byte version){ for (int i = 0; i < signature.length; i++) { if(reader.readByte() != signature[i]){ return false; } } return reader.readByte() == version; } // TODO: freespaceID should not be passed here, it should be taken from SystemData public abstract void writeFixedPart( LocalObjectContainer file, boolean startFileLockingThread, boolean shuttingDown, StatefulBuffer writer, int blockSize); public abstract void writeTransactionPointer(Transaction systemTransaction, int transactionPointer); protected void writeTransactionPointer(Transaction systemTransaction, int transactionPointer, final int address, final int offset) { StatefulBuffer bytes = new StatefulBuffer(systemTransaction, address, TRANSACTION_POINTER_LENGTH); bytes.moveForward(offset); bytes.writeInt(transactionPointer); bytes.writeInt(transactionPointer); if (Debug4.xbytes) { bytes.checkXBytes(false); } // Dangerous write. // On corruption transaction pointers will not be the same and nothing will happen. bytes.write(); } public void writeVariablePart(LocalObjectContainer file){ writeVariablePart(file, false); } public abstract void writeVariablePart(LocalObjectContainer file, boolean shuttingDown); public static boolean lockedByOtherSession(LocalObjectContainer container, long lastAccessTime) { return container.needsLockFileThread() && ( lastAccessTime != 0); } public abstract void readIdentity(LocalObjectContainer container); public abstract Runnable commit(boolean shuttingDown); }