/* * Copyright 2010 Paula Gearon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mulgara.util.io; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import org.apache.log4j.Logger; /** * An abstraction for reading and writing to files with Long offsets. * @author Paula Gearon * */ public abstract class LBufferedFile { private final static Logger logger = Logger.getLogger(LBufferedFile.class); /** The property for the io type. May be "mapped" or "explicit" */ public static final String IO_TYPE_PROP = "mulgara.xa.forceIOType"; /** Enumeration of the different io types */ enum IOType { MAPPED, EXPLICIT }; private static final IOType ioType; static { // initialize the type of file access to use: memory mapped files, or explicit read/write operations // configured with mulgara.xa.forceIOType String forceIOTypeProp = System.getProperty(IO_TYPE_PROP, "mapped"); if (forceIOTypeProp.equalsIgnoreCase(IOType.MAPPED.name())) { ioType = IOType.MAPPED; } else if (forceIOTypeProp.equalsIgnoreCase(IOType.EXPLICIT.name())) { ioType = IOType.EXPLICIT; } else { logger.warn("Invalid value for property mulgara.xa.forceIOType: " + forceIOTypeProp); ioType = IOType.MAPPED; } } /** The file being accessed */ protected RandomAccessFile file; /** * Creates new buffered access for a file. * @param file the file to provide buffered access for. */ LBufferedFile(RandomAccessFile file) { this.file = file; } /** * Reads a buffer from a file, at a given position. * @param offset The offset to get the buffer from. * @param length The required size of the buffer. * @return The buffer that was read. */ public abstract ByteBuffer read(long offset, int length) throws IOException; /** * Create a buffer that will be used for writing to a file at a given location. * @param offset The location in the file that the buffer will write to. * @param length The size of the buffer. * @return The buffer for accessing that part of the file. */ public abstract ByteBuffer allocate(long offset, int length) throws IOException; /** * Puts the contents of a buffer into the file. This will go back to wherever * it was supposed to go. * @param data The buffer to be written. */ public abstract void write(ByteBuffer data) throws IOException; /** * Moves the current file position. * @param offset The new position in the file. */ public abstract void seek(long offset) throws IOException; /** * @return The page size used internally by the implementation, or 0 if not paged. */ public abstract int getPageSize(); /** * Truncates the file to a given size, or prepares the file for truncation * if it is read-only. * @param offset The offset into the file to trancate the size to. */ public abstract void truncate(long offset) throws IOException; /** * Closes the file resource. */ public void close() throws IOException { file.close(); } /** * Ensures that all data written to this file is forced to disk. * @throws IOException If there is an IO error accessing the disk. */ public void force() throws IOException { file.getChannel().force(false); } /** * Register a listener that will be called when Remaps occur. * The implementation of this class may not do any remapping. * @param l The listener to register. */ public abstract void registerRemapListener(Runnable l); static LBufferedFile createWritable(RandomAccessFile f, int recordSize) throws IOException { if (ioType == IOType.MAPPED) { return new LMappedBufferedFileRW(f, recordSize); } else if (ioType == IOType.EXPLICIT) { return new LIOBufferedFile(f); } else { throw new IllegalArgumentException("Invalid BlockFile ioType."); } } /** * Create a buffered file, taking over the RandomAccessFile that is provided. * @param f The file to provide buffered access to. * @return The buffered file. * @throws IOException An error opening the file. */ static LBufferedFile createReadOnly(RandomAccessFile f) throws IOException { if (ioType == IOType.MAPPED) { return new LMappedBufferedFileRO(f); } else if (ioType == IOType.EXPLICIT) { return new LReadOnlyIOBufferedFile(f); } else { throw new IllegalArgumentException("Invalid BlockFile ioType."); } } /** * Create a buffered file using a filename. * @param fileName The name of the file to provide buffered access to. * @return The readonly buffered file. * @throws IOException An error opening the file. */ public static LBufferedFile createWritable(String fileName, int recordSize) throws IOException { return createWritable(new RandomAccessFile(fileName, "rw"), recordSize); } /** * Create a buffered file using a filename. * @param fileName The file to provide buffered access to. * @return The readonly buffered file. * @throws IOException An error opening the file. */ public static LBufferedFile createWritable(File file, int recordSize) throws IOException { return createWritable(new RandomAccessFile(file, "rw"), recordSize); } /** * Create a buffered file using a filename. * @param fileName The name of the file to provide buffered access to. * @return The readonly buffered file. * @throws IOException An error opening the file. */ public static LBufferedFile createReadOnly(String fileName) throws IOException { return createReadOnly(new RandomAccessFile(fileName, "r")); } /** * Create a buffered file using a filename. * @param file The file to provide buffered access to. * @return The readonly buffered file. * @throws IOException An error opening the file. */ public static LBufferedFile createReadOnly(File file) throws IOException { return createReadOnly(new RandomAccessFile(file, "r")); } // debug abstract byte[] dump() throws IOException; }