All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.net.msrp.FileDataContainer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright � Jo�o Antunes 2008 This file is part of MSRP Java Stack.
 * 
 * MSRP Java Stack 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.
 * 
 * MSRP Java Stack 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 MSRP Java Stack. If not, see .
 */
package javax.net.msrp;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import javax.net.msrp.exceptions.IllegalUseException;
import javax.net.msrp.exceptions.NotEnoughDataException;
import javax.net.msrp.exceptions.NotEnoughStorageException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An implementation of the data container class.
 * 

* It uses a file read from/write to the data associated with an MSRP message * @see DataContainer * * @author Jo�o Andr� Pereira Antunes 2008 * */ public class FileDataContainer extends DataContainer { private static final String IOERR = "I/O problems: "; /** The logger associated with this class */ private static final Logger logger = LoggerFactory.getLogger(FileDataContainer.class); /** * Original File reference */ private File file; /** * Object that contains the file */ private RandomAccessFile randomAccessFile; /** * The FileChannel used to read and write bytes */ private FileChannel fileChannel; /* * TODO: WORK IN PROGRESS field that will be used to optimise the writes * on the file so that we don't have too much of an overhead with IOs * * currently used for all operations of file channel that require a ByteBuffer */ private ByteBuffer auxByteBuffer; private final Object readOffsetLock = new Object(); private Long currentReadOffset = new Long(0); /** * Creates a new DataContainer based on the given file, The file must be * readable and writable. *

* Note: if the file exists it's content will be overwritten * * @param file the given file * @throws FileNotFoundException if the file was not found * @throws SecurityException if a security manager exists and its checkRead * method denies read access to the file or the mode is "rw" and * the security manager's checkWrite method denies write access * to the file */ public FileDataContainer(File file) throws FileNotFoundException, SecurityException { this.file = file; randomAccessFile = new RandomAccessFile(file, "rw"); fileChannel = randomAccessFile.getChannel(); logger.trace("Created a FileDataContainer for file: " + file.getAbsolutePath()); } /** * Specific method to retrieve the File associated with this container * * @return the File object, used to store the data */ public File getFile() { return file; } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#size() */ @Override public long size() { try { return fileChannel.size(); } catch (IOException e) { logger.error(IOERR, e); } return 0; } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#currentReadOffset() */ @Override public long currentReadOffset() { synchronized (readOffsetLock) { return currentReadOffset.longValue(); } } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#hasDataToRead() */ @Override public boolean hasDataToRead() { synchronized (readOffsetLock) { try { if (currentReadOffset.longValue() < fileChannel.size()) return true; } catch (IOException e) { logger.error(IOERR, e); } return false; } } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#put(long, byte[]) */ @Override public void put(long startingIndex, byte[] dataToPut) throws NotEnoughStorageException, Exception { auxByteBuffer = ByteBuffer.wrap(dataToPut); fileChannel.write(auxByteBuffer, startingIndex); } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#put(byte) */ @Override public void put(byte byteToPut) throws NotEnoughStorageException, IOException { byte[] auxByteArray = new byte[1]; auxByteArray[1] = byteToPut; auxByteBuffer = ByteBuffer.wrap(auxByteArray); int result = fileChannel.write(auxByteBuffer); if (result == 0 || result == -1) throw new NotEnoughStorageException(); } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#put(long, byte) * * TODO: if needed use a small buffer in order to make writes more efficient. */ @Override public void put(long startingIndex, byte byteToPut) throws NotEnoughStorageException, IOException { byte[] auxByteArray = new byte[1]; auxByteArray[1] = byteToPut; auxByteBuffer = ByteBuffer.wrap(auxByteArray); int result = fileChannel.write(auxByteBuffer, startingIndex); if (result == 0 || result == -1) throw new NotEnoughStorageException(); } @Override public ByteBuffer get(long offsetIndex, long size) throws NotEnoughDataException, IOException, IllegalUseException { if (size > MAXIMUMNUMBERBYTES) throw new IllegalUseException("Can't retrieve more than " + MAXIMUMNUMBERBYTES + "bytes to memory"); if (size == ALLBYTES) { if ((fileChannel.size() - offsetIndex) > MAXIMUMNUMBERBYTES) throw new IllegalUseException("Can't retrieve more than " + MAXIMUMNUMBERBYTES + "bytes to memory"); auxByteBuffer = ByteBuffer.allocate((int) (fileChannel.size() - offsetIndex)); int result = fileChannel.read(auxByteBuffer, auxByteBuffer.capacity()); if (result == 0 || result == -1) throw new NotEnoughDataException(); return auxByteBuffer; } else { auxByteBuffer = ByteBuffer.allocate((int) size); int result = fileChannel.read(auxByteBuffer, offsetIndex); if (result == -1 || result == 0 || result != size) throw new NotEnoughDataException(); return auxByteBuffer; } } @Override public void rewindRead(long nrPositions) { /* * It's only needed to change the value of the currentReadOffset * variable because the get method makes sure that the position of the * reader of the file is put into the position specified by that * variable prior to reading data from it */ synchronized (readOffsetLock) { currentReadOffset -= nrPositions; } } @Override public int get(byte[] dst, int offset) throws IndexOutOfBoundsException, Exception { return get(dst, offset, dst.length - offset); } @Override public int get(byte[] dst, int offset, int limit) throws IndexOutOfBoundsException, Exception { if (offset > dst.length - 1) throw new IndexOutOfBoundsException(); synchronized (readOffsetLock) { int bytesToCopy = 0; int space = dst.length - offset; if (space < limit) space = limit; long remainingDataBytes = fileChannel.size() - currentReadOffset.longValue(); if (remainingDataBytes < space) bytesToCopy = (int) remainingDataBytes; else bytesToCopy = space; auxByteBuffer = ByteBuffer.allocate(bytesToCopy); int result = fileChannel.read(auxByteBuffer); if (result == 0 || result == -1) throw new NotEnoughDataException(); if (result != bytesToCopy) throw new InternalError( "Something went wrong, it should have copied " + bytesToCopy + " but instead copied " + result); System.arraycopy(auxByteBuffer.array(), 0, dst, offset, result); currentReadOffset += result; return result; } } /* (non-Javadoc) * @see javax.net.msrp.DataContainer#dispose() */ @Override public void dispose() { try { fileChannel.close(); randomAccessFile.close(); } catch (IOException e) { logger.error(IOERR, e); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy