/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.io.raw; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import xxl.core.io.FilesystemOperations; import xxl.core.util.Arrays; import xxl.core.util.WrappingRuntimeException; /** * This class provides a simple filesystem based on an array of RawAccesses. * The file system manages a fixed number of files (maximum). The check for equality is * case sensitive (like under Linux). * Directories are not supported. */ public class RawAccessArrayFilesystemOperations implements FilesystemOperations { /** * Array of RawAccesses used for the content of the files. */ protected RawAccess ras[]; /** * Filenames inside the file system. */ protected String filenames[]; /** * Determines iff new space at the end a RandomAccessFile should be initialized * will 0-values or not. <code>true</code> is the standard, because it * is fully compliant with java.io.RandomAccessFile. */ protected boolean initBlocksAtEOF; /** * Determines if the files have been created so far. */ protected boolean filesCreated[]; /** * The implementation needs a file that exists inside the file system. The file is never really used, * just opened as read only and immediately closed again. This parameter only exists because of the inflexible * implementation of RandomAccessFile. */ protected File dummyFile; /** Maximum number of files (number of RawAccesses). */ protected int maxNumberOfFiles; /** Current number of files (filenames used). */ protected int currentNumberOfFiles; /** * Creates a simple file system based on a number of RawAccesses. * Initially, the given filenames are mapped to the corresponding RawAccesses. * If the corresponding value of filesCreated is true, then it is assumed * that the RawAccess already contains data which is the content of the * file. If filesCreated is false, then the RawAccess is overwritten. * * @param ras an array of RawAccesses (@see PartitionRawAccess and @see RawAccessUtils.rawAccessPartitioner) * @param filenames names of the files (initially). The length of the array must * lower or equal compared to the RawAccess array. * @param filesCreated determines if the files have content at the beginning. * @param dummyFile The implementation needs a file * that exists inside the file system. The file is never really used, * just opened as read only and immediately closed again. This parameter * only exists because of the inflexible implementation of RandomAccessFile. * @param initBlocksAtEOF Determines iff new space at the end a RandomAccessFile should * be initialized will 0-values or not. <code>true</code> is the standard, because it * is fully compliant with java.io.RandomAccessFile. */ public RawAccessArrayFilesystemOperations(RawAccess ras[], String filenames[], boolean filesCreated[], File dummyFile, boolean initBlocksAtEOF) { this.maxNumberOfFiles = ras.length; if (filenames.length > maxNumberOfFiles ) throw new RuntimeException("Number of filenames is bigger than the number of RawAccesses"); if (filenames.length != filesCreated.length) throw new RuntimeException("Number of filenames and number of entries in filesCreated is not the same"); this.currentNumberOfFiles = filenames.length; // Rebuild the arrays this.filenames = new String[maxNumberOfFiles]; this.filesCreated = new boolean[maxNumberOfFiles]; for (int i=0; i<filenames.length; i++) { this.filenames[i] = new String(filenames[i]); this.filesCreated[i] = filesCreated[i]; } this.ras = ras; this.dummyFile = dummyFile; this.initBlocksAtEOF = initBlocksAtEOF; } /** * Creates a simple file system based on a number of RawAccesses. * Initially, the given filenames are mapped to the corresponding RawAccesses. * If the value of filesCreated is true, then it is assumed * that all RawAccesses already contain data which is the content of the * file. If filesCreated is false, then the RawAccesses become overwritten. * * @param ras an array of RawAccesses (@see PartitionRawAccess and @see RawAccessUtils.rawAccessPartitioner) * @param filenames names of the files (initially). The length of the array must * lower or equal compared to the RawAccess array. * @param filesCreated determines if the files have content at the beginning. * @param dummyFile The implementation needs a file * that exists inside the file system. The file is never really used, * just opened as read only and immediately closed again. This parameter * only exists because of the inflexible implementation of RandomAccessFile. * @param initBlocksAtEOF Determines iff new space at the end a RandomAccessFile should * be initialized will 0-values or not. <code>true</code> is the standard, because it * is fully compliant with java.io.RandomAccessFile. */ public RawAccessArrayFilesystemOperations(RawAccess ras[], String filenames[], boolean filesCreated, File dummyFile, boolean initBlocksAtEOF) { this(ras,filenames,Arrays.newBooleanArray(filenames.length,filesCreated),dummyFile, initBlocksAtEOF); } /** * Creates a simple file system based on a number of RawAccesses. * Initially, no files exist on the file system. * * @param ras an array of RawAccesses (@see PartitionRawAccess and @see RawAccessUtils.rawAccessPartitioner) * @param dummyFile The implementation needs a file * that exists inside the file system. The file is never really used, * just opened as read only and immediately closed again. This parameter * only exists because of the inflexible implementation of RandomAccessFile. * @param initBlocksAtEOF Determines iff new space at the end a RandomAccessFile should * be initialized will 0-values or not. <code>true</code> is the standard, because it * is fully compliant with java.io.RandomAccessFile. */ public RawAccessArrayFilesystemOperations(RawAccess ras[], File dummyFile, boolean initBlocksAtEOF) { this(ras, new String[0], new boolean[0], dummyFile, initBlocksAtEOF); } /** * Determines the position of the file inside the array. * @param filename Name of the file to be searched. * @return the position of the file inside the array. */ private int getIndex(String filename) { if (currentNumberOfFiles>0) for (int i=0; i<maxNumberOfFiles; i++) if (filename.equals(filenames[i])) return i; return -1; } /** * Creates the file on the file system without accessing it. * @param filename the name of the file. * @return the index inside the filenames array. */ private int createFileInternal(String filename) { if (currentNumberOfFiles < maxNumberOfFiles) { for (int i=0; i<maxNumberOfFiles; i++) { if (filenames[i]==null) { filenames[i] = new String(filename); filesCreated[i] = false; currentNumberOfFiles++; return i; } } } return -1; } /** * Creates the file on the file system without accessing it. * @param filename the name of the file. * @return true iff the operation completed successfully. */ public boolean createFile(String filename) { return (createFileInternal(filename)>=0); } /** * Opens the file and returns a RandomAccessFile. * @param fileName the name of the file. * @param mode the access mode ("r" or "rw"). * @return the new RandomAccessFile or null, if the operation was not successful. */ public RandomAccessFile openFile(String fileName, String mode) { try { int index = getIndex(fileName); if (index==-1) { index = createFileInternal(fileName); // create new file if (index==-1) return null; } if (index>=0) { // File found (exists) RandomAccessFile ra = new RawAccessRAF( ras[index], !filesCreated[index], dummyFile, initBlocksAtEOF // ,mode ); filesCreated[index] = true; return ra; } else return null; } catch (IOException ie) { throw new WrappingRuntimeException(ie); } } /** * Determines if the file exists or not. * @param fileName the name of the file to be checked. * @return true iff the file exists. */ public boolean fileExists(String fileName) { return getIndex(fileName)>=0; } /** * Renames the name of the file to a new name. * @param oldName the old name of the file. * @param newName the new name of the file. * @return true iff the operation completed successfully. */ public boolean renameFile(String oldName, String newName) { int index = getIndex(oldName); if (index>=0) { int indexNew = getIndex(newName); if (indexNew==-1) // no duplicate file names filenames[index] = newName; return true; } else return false; } /** * Deletes the file. * @param fileName the name of the file. * @return true iff the operation completed successfully. */ public boolean deleteFile(String fileName) { int index = getIndex(fileName); if (index>=0) { filenames[index] = null; filesCreated[index] = false; currentNumberOfFiles--; return true; } else return false; } }