Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  jDTAUS - DTAUS fileformat.
   *  Copyright (c) 2005 Christian Schulte <cs@schulte.it>
   *
   *  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 2.1 of the License, or 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, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 package org.jdtaus.core.io.util;
 
 import  org.jdtaus.core.container.ContainerFactory;
 import  org.jdtaus.core.container.ContextFactory;
 import  org.jdtaus.core.container.ContextInitializer;
 import  org.jdtaus.core.container.Implementation;
 import  org.jdtaus.core.container.ModelFactory;
 import  org.jdtaus.core.container.Properties;
 import  org.jdtaus.core.container.Property;
 import  org.jdtaus.core.container.PropertyException;
 import  org.jdtaus.core.text.Message;
 import  org.jdtaus.core.io.FileOperations;
 import  org.jdtaus.core.io.StructuredFile;
 import  org.jdtaus.core.io.StructuredFileListener;
 import  org.jdtaus.core.lang.spi.MemoryManager;
 import  org.jdtaus.core.monitor.Task;
 import  org.jdtaus.core.monitor.spi.TaskMonitor;

StructuredFile implementation based on FileOperations.

This implementation performs read-ahead caching for the readBlock() methods. Changes done via the writeBlock() methods will only be cached if the blocks beeing changed were read-ahead into the cache via the readBlock() methods before. All other writes will directly be performed with calls to FileOperations methods. The flush() method must be used to write out cached changes to the underlying FileOperations implementation.

Note:
This implementation is not thread-safe. Concurrent changes to the underlying FileOperations implementation are not supported.

Author(s):
Christian Schulte
Version:
$Id: StructuredFileOperations.java 2927 2007-04-20 19:53:53Z schulte2005 $
 
 public final class StructuredFileOperations implements StructuredFile
 {
     //--Fields------------------------------------------------------------------
 
    
Cache for readAhead blocks.
 
     private byte[] cache;

    
Index of the block starting at cache[0].
 
     private long cacheIndex;

    
Number of blocks read-ahead into cache.
 
     private int cacheMaxIndex;

    
Information about changes in memory which need to be persisted.
 
     private boolean[] dirtyCache;

    
Pre-allocated temporary buffer.
 
     private byte[] minimumBuffer;

    
List for StructuredFileListeners.
 
     private final EventListenerList fileListeners = new EventListenerList();
 
     //------------------------------------------------------------------Fields--
     //--Implementation----------------------------------------------------------
 
     // This section is generated by jdtaus-source-plugin.
 
    
Meta-data describing the implementation.
 
     private static final Implementation META =
         ModelFactory.getModel().getModules().
         getImplementation(StructuredFileOperations.class.getName());
 
     //----------------------------------------------------------Implementation--
     //--Constructors------------------------------------------------------------
 
     // This section is generated by jdtaus-source-plugin.
 
    
Initializes the properties of the instance.

Parameters:
meta the property values to initialize the instance with.
Throws:
NullPointerException if meta is null.
    protected void initializeProperties(final Properties meta)
    {
        Property p;
        if(meta == null)
        {
            throw new NullPointerException("meta");
        }
        p = meta.getProperty("minBufferedBlocks");
        this. = ((java.lang.Integerp.getValue()).intValue();
        p = meta.getProperty("readAhead");
        this. = ((java.lang.Integerp.getValue()).intValue();
        p = meta.getProperty("blockSize");
        this. = ((java.lang.Integerp.getValue()).intValue();
    }
    //------------------------------------------------------------Constructors--
    //--Dependencies------------------------------------------------------------
    // This section is generated by jdtaus-source-plugin.

    
Configured TaskMonitor implementation.
    private transient TaskMonitor _dependency1;

    
Gets the configured TaskMonitor implementation.

Returns:
the configured TaskMonitor implementation.
    private TaskMonitor getTaskMonitor()
    {
        TaskMonitor ret = null;
        if(this. != null)
        {
           ret = this.;
        }
        else
        {
            ret = (TaskMonitor) ContainerFactory.getContainer().
                getDependency(StructuredFileOperations.class,
                "TaskMonitor");
            if(ModelFactory.getModel().getModules().
                getImplementation(StructuredFileOperations.class.getName()).
                getDependencies().getDependency("TaskMonitor").
                isBound())
            {
                this. = ret;
            }
        }
        if(ret instanceof ContextInitializer && !((ContextInitializer) ret).
            isInitialized(ContextFactory.getContext()))
        {
            ((ContextInitializer) ret).initialize(ContextFactory.getContext());
        }
        return ret;
    }
    
Configured MemoryManager implementation.
    private transient MemoryManager _dependency0;

    
Gets the configured MemoryManager implementation.

Returns:
the configured MemoryManager implementation.
    private MemoryManager getMemoryManager()
    {
        MemoryManager ret = null;
        if(this. != null)
        {
           ret = this.;
        }
        else
        {
            ret = (MemoryManager) ContainerFactory.getContainer().
                getDependency(StructuredFileOperations.class,
                "MemoryManager");
            if(ModelFactory.getModel().getModules().
                getImplementation(StructuredFileOperations.class.getName()).
                getDependencies().getDependency("MemoryManager").
                isBound())
            {
                this. = ret;
            }
        }
        if(ret instanceof ContextInitializer && !((ContextInitializer) ret).
            isInitialized(ContextFactory.getContext()))
        {
            ((ContextInitializer) ret).initialize(ContextFactory.getContext());
        }
        return ret;
    }
    //------------------------------------------------------------Dependencies--
    //--Properties--------------------------------------------------------------
    // This section is generated by jdtaus-source-plugin.

    
Property minBufferedBlocks.

Serial:
    private int _minBufferedBlocks;

    
Gets the value of property minBufferedBlocks.

Returns:
the value of property minBufferedBlocks.
    protected int getMinBufferedBlocks()
    {
        return this.;
    }

    
Property readAhead.

Serial:
    private int _readAhead;

    
Gets the value of property readAhead.

Returns:
the value of property readAhead.
    protected int getReadAhead()
    {
        return this.;
    }

    
Property blockSize.

Serial:
    private int _blockSize;

    
Gets the value of property blockSize.

Returns:
the value of property blockSize.
    public int getBlockSize()
    {
        return this.;
    }
    //--------------------------------------------------------------Properties--
    //--StructuredFile----------------------------------------------------------
    public long getBlockCount() throws IOException
    {
        return this.getFileOperations().getLength() / this.getBlockSize();
    }
    public void deleteBlocks(final long index,
        final long countthrows IOException
    {
        final long blockCount = this.getBlockCount();
        // Preconditions.
        if(index < 0L || index > blockCount - count)
        {
            throw new ArrayIndexOutOfBoundsException((intindex);
        }
        if(count <= 0 || count > blockCount - index)
        {
            throw new ArrayIndexOutOfBoundsException((intcount);
        }
        this.deleteBlocksImpl(indexcountblockCount);
    }
    private void deleteBlocksImpl(final long indexfinal long count,
        final long blockCountthrows IOException
    {
        final byte[] buf;
        final long block = index + count;
        final DeleteBlocksTask task = new DeleteBlocksTask();
        long toMoveByte = (blockCount - block) * this.getBlockSize();
        long readPos = block * this.getBlockSize();
        long writePos = index * this.getBlockSize();
        // Flush the cache.
        if(!(this. < 0) && this. >= index)
        {
            this.flush();
            this. = -1L;
        }
        // No blocks are following the ones to remove.
        if(toMoveByte == 0L)
        {
            this.getFileOperations().setLength(this.getFileOperations().
                getLength() - count * this.getBlockSize());
            this.fireBlocksDeleted(indexcount);
            return;
        }
        buf = this.newTemporaryBuffer(toMoveByte >
            . ? . : (inttoMoveByte);
        task.setIndeterminate(false);
        task.setMinimum(0);
        task.setMaximum(toMoveByte > . ?
            . : (inttoMoveByte);
        task.setProgress(0);
        this.getTaskMonitor().monitor(task);
        try
        {
            // Move following blocks to the position of the first block to
            // remove.
            while(toMoveByte > 0L)
            {
                this.getFileOperations().setFilePointer(readPos);
                final int len = toMoveByte <= buf.length ?
                    (inttoMoveByte : buf.length;
                int read = 0;
                int total = 0;
                do
                {
                    read = this.getFileOperations().
                        read(buftotallen - total);
                    if(read == -1)
                    {
                        throw new EOFException();
                    }
                    else
                    {
                        total += read;
                    }
                } while(total < len);
                // Move the block count blocks to the beginning.
                this.getFileOperations().setFilePointer(writePos);
                this.getFileOperations().write(buf, 0, len);
                readPos += len;
                writePos += len;
                toMoveByte -= len;
                task.setProgress(task.getProgress() + len > . ?
                    . : task.getProgress() + len);
            }
            // Truncate the file.
            this.getFileOperations().setLength(this.getFileOperations().
                getLength() - count * this.getBlockSize());
            this.fireBlocksDeleted(indexcount);
        }
        finally
        {
            this.getTaskMonitor().finish(task);
        }
    }
    public void insertBlocks(final long index,
        final long countthrows IOException
    {
        final long blockCount = this.getBlockCount();
        // Preconditions.
        if(index < 0L || index > blockCount)
        {
            throw new ArrayIndexOutOfBoundsException((intindex);
        }
        if(count <= 0L || count > . - blockCount)
        {
            throw new ArrayIndexOutOfBoundsException((intcount);
        }
        this.insertBlocksImpl(indexcountblockCount);
    }
    private void insertBlocksImpl(final long indexfinal long count,
        final long blockCountthrows IOException
    {
        final byte[] buf;
        final InsertBlocksTask task = new InsertBlocksTask();
        long toMoveByte = (blockCount - index) * this.getBlockSize();
        long readPos = blockCount * this.getBlockSize();
        long writePos = readPos + count * this.getBlockSize();
        // Flush the cache.
        if(!(this. < 0) && this. >= index)
        {
            this.flush();
            this. = -1L;
        }
        // Increase the length of the file.
        this.getFileOperations().setLength(this.getFileOperations().
            getLength() + this.getBlockSize() * count);
        // New blocks are inserted at the end of the file.
        if(toMoveByte <= 0L)
        {
            this.fireBlocksInserted(indexcount);
            return;
        }
        buf = this.newTemporaryBuffer(toMoveByte > . ?
            . : (inttoMoveByte);
        task.setIndeterminate(false);
        task.setMinimum(0);
        task.setMaximum(toMoveByte > . ?
            . : (inttoMoveByte);
        task.setProgress(0);
        this.getTaskMonitor().monitor(task);
        try
        {
            // Move all blocks from index inclusive count blocks to the end of
            // the file.
            while(toMoveByte > 0L)
            {
                final int moveLen = buf.length >= toMoveByte ?
                    (inttoMoveByte : buf.length;
                readPos -= moveLen;
                writePos -= moveLen;
                this.getFileOperations().setFilePointer(readPos);
                int read = 0;
                int total = 0;
                do
                {
                    read = this.getFileOperations().
                        read(buftotalmoveLen - total);
                    if(read == -1)
                    {
                        throw new EOFException();
                    }
                    else
                    {
                        total += read;
                    }
                } while(total < moveLen);
                // Move the block count blocks to the end.
                this.getFileOperations().setFilePointer(writePos);
                this.getFileOperations().write(buf, 0, moveLen);
                toMoveByte -= moveLen;
                task.setProgress(
                    task.getProgress() + moveLen > . ?
                        . : task.getProgress() + moveLen);
            }
            this.fireBlocksInserted(indexcount);
        }
        finally
        {
            if(task != null)
            {
                this.getTaskMonitor().finish(task);
            }
        }
    }
    public void readBlock(final long blockfinal int off,
        final byte[] bufthrows IOException
    {
        this.readBlock(blockoffbuf, 0, buf.length);
    }
    public void readBlock(final long blockfinal int offfinal byte[] buf,
        final int indexfinal int lengththrows IOException
    {
        this.assertValidArguments(blockoffbufindexlength);
        // Fill the cache.
        this.readAhead(blockthis.getBlockCount());
        // Copy from cache.
        System.arraycopy(this.,
            ((int) ((block - this.) * this.getBlockSize())) + off,
            bufindexlength);
    }
    public void writeBlock(final long blockfinal int off,
        final byte[] bufthrows IOException
    {
        this.writeBlock(blockoffbuf, 0, buf.length);
    }
    public void writeBlock(final long blockfinal int offfinal byte[] buf,
        final int indexfinal int lengththrows IOException
    {
        this.assertValidArguments(blockoffbufindexlength);
        if(!(this. < 0L) && block >= this. &&
            block <= this. + this.)
        {
            System.arraycopy(bufindexthis.,
                (int) (block - this.) * this.getBlockSize() + off,
                length);
            this.[(int) (block - this.)] = true;
        }
        else
        {
            this.getFileOperations().
                setFilePointer(block * this.getBlockSize() + off);
            this.getFileOperations().write(bufindexlength);
        }
    }
    public void addStructuredFileListener(
        final StructuredFileListener listener)
    {
        this..add(StructuredFileListener.classlistener);
    }
    public void removeStructuredFileListener(
        final StructuredFileListener listener)
    {
        this..remove(StructuredFileListener.classlistener);
    }
    public StructuredFileListener[] getStructuredFileListeners()
    {
        return (StructuredFileListener[]) this..getListeners(
            StructuredFileListener.class);
    }
    //----------------------------------------------------------StructuredFile--
    //--StructuredFileOperations------------------------------------------------

    
Underlying FileOperations.
    private FileOperations fileOperations;

    
Message: Removing blocks.
    private static final class DeleteBlocksMessage extends Message
    {
        private static final Object[] NO_ARGS = {};
        public Object[] getFormatArguments(final Locale locale)
        {
            return ;
        }
        public String getText(final Locale locale)
        {
            return StructuredFileOperationsBundle.
                getDeleteBlocksTaskText(locale);
        }
    }

    
Message: Inserting blocks.
    private static final class InsertBlocksMessage extends Message
    {
        private static final Object[] NO_ARGS = {};
        public Object[] getFormatArguments(final Locale locale)
        {
            return ;
        }
        public String getText(final Locale locale)
        {
            return StructuredFileOperationsBundle.
                getInsertBlocksTaskText(locale);
        }
    }

    
Task deleting blocks.
    private static class DeleteBlocksTask extends Task
    {

        
Description of the task.

Serial:
        private Message description;
        public Message getDescription()
        {
            if(this. == null)
            {
                this. =
                    new StructuredFileOperations.DeleteBlocksMessage();
            }
            return this.;
        }
    }

    
Task inserting blocks.
    private static class InsertBlocksTask extends Task
    {

        
Description of the task.

Serial:
        private Message description;
        public Message getDescription()
        {
            if(this. == null)
            {
                this. =
                    new StructuredFileOperations.InsertBlocksMessage();
            }
            return this.;
        }
    }

    
Creates a new StructuredFileOperations instance.

Parameters:
blockSize Number of bytes per block.
fileOperations FileOperations implementation to operate on.
Throws:
NullPointerException if fileOperations is null.
IllegalArgumentException if blockSize cannot be used with fileOperations.
IOException if getting the length from the fileOperations fails.
    public StructuredFileOperations(final int blockSize,
        final FileOperations fileOperationsthrows IOException
    {
        super();
        this.initializeProperties(.getProperties());
        this.assertValidProperties();
        if(fileOperations == null)
        {
            throw new NullPointerException("fileOperations");
        }
        this. = blockSize;
        this. = fileOperations;
        final int minBufferedBlocks = this.getMinBufferedBlocks();
        final int readAhead = this.getReadAhead();
        this. = this.getMemoryManager().
            allocateBytes(minBufferedBlocks * blockSize);
        this. = this.getMemoryManager().
            allocateBytes(blockSize * readAhead);
        this. = this.getMemoryManager().
            allocateBoolean(readAhead);
        this. = -1L;
        this. = -1;
        this.assertValidFileLength();
    }

    
Gets the FileOperations implementation operations are performed with.

Returns:
the FileOperations implementation operations are performed with.
    public FileOperations getFileOperations()
    {
        return this.;
    }

    
Flushes internal caches.

Must be called at least once after finishing work with an instance to write out cached changes.

Throws:
IOError for unrecoverable I/O errors.
    public void flush() throws IOException
    {
        if(this. >= 0L)
        {
            int writeOffset = 0;
            int writeLength = 0;
            final long blockCount = this.getBlockCount();
            final int readAhead = this.getReadAhead();
            final int toWrite = blockCount - this. < readAhead ?
                (int) (blockCount - this.) : readAhead;
            for(int i = 0; i < toWritei++)
            {
                if(!this.[i])
                {
                    if (writeLength > 0)
                    {
                        this.getFileOperations().setFilePointer(
                            (this. + writeOffset) * getBlockSize());
                        this.getFileOperations().write(this.writeOffset *
                            this.getBlockSize(), writeLength);
                    }
                    writeOffset = i + 1;
                    writeLength = 0;
                }
                else
                {
                    this.[i] = false;
                    writeLength += this.getBlockSize();
                }
            }
            if(writeLength > 0)
            {
                this.getFileOperations().setFilePointer(
                    (this. + writeOffset) * this.getBlockSize());
                this.getFileOperations().write(this.,
                    writeOffset * this.getBlockSize(), writeLength);
            }
        }
    }

    
Checks arguments provided to the readBlock and writeBlock methods.

Throws:
NullPointerException if buf is null.
IndexOutOfBoundsException if block is negative, greater than or equal to getBlockCount(), or off is negative, greater than or equal to getBlockSize(), or index is negative, greater than or equal to the length of buf, or length is negative or greater than the length of buf minus index or greater than getBlockSize() - off.
    private void assertValidArguments(final long blockfinal int off,
        final byte[] buffinal int indexfinal int lengththrows
    {
        final long blockCount = this.getBlockCount();
        if(buf == null)
        {
            throw new NullPointerException("buf");
        }
        if(block < 0 || block >= blockCount)
        {
            throw new ArrayIndexOutOfBoundsException((intblock);
        }
        if(off < 0 || off >= this.getBlockSize())
        {
            throw new ArrayIndexOutOfBoundsException((intoff);
        }
        if(index < 0 || index >= buf.length)
        {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        if(length < 0L || length > buf.length - index ||
            length > this.getBlockSize() - off)
        {
            throw new ArrayIndexOutOfBoundsException(length);
        }
    }

    
Checks the length of the provided FileOperations implementation against property blockSize.

Throws:
IllegalArgumentException if the combination of property blockSize and getFileOperations().getLength() is invalid.
IOException if the getting the length fails.
    private void assertValidFileLength() throws IOException
    {
        if(this.getFileOperations() != null)
        {
            if(this.getFileOperations().getLength() %
                this.getBlockSize() != 0L)
            {
                throw new IllegalArgumentException(Long.toString(
                    this.getFileOperations().getLength() %
                    this.getBlockSize()));
            }
        }
    }

    
Checks configured properties.

Throws:
PropertyException for illegal property values.
    private void assertValidProperties()
    {
        final int minBufferedBlocks = this.getMinBufferedBlocks();
        final int readAhead = this.getReadAhead();
        final int blockSize = this.getBlockSize();
        // minBufferedBlocks must be a positive integer.
        if(!(minBufferedBlocks > 0))
        {
            throw new PropertyException("minBufferedBlocks",
                Integer.toString(minBufferedBlocks));
        }
        // readAhead must be a positive integer.
        if(!(readAhead > 0))
        {
            throw new PropertyException("readAhead",
                Integer.toString(readAhead));
        }
        // blockSize must be a positive integer.
        if(!(blockSize > 0))
        {
            throw new PropertyException("blockSize",
                Integer.toString(blockSize));
        }
    }

    
Notifies all registered StructuredFileListeners about inserted blocks.

Parameters:
index the index new blocks were inserted.
insertedBlocks the number of blocks which were inserted at index.
Throws:
IOException if reading or writing fails.
    private void fireBlocksInserted(final long index,
        final long insertedBlocksthrows IOException
    {
        final Object[] listeners = this..getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2)
        {
            if (listeners[i] == StructuredFileListener.class)
            {
                ((StructuredFileListener) listeners[i + 1]).
                    blocksInserted(indexinsertedBlocks);
            }
        }
    }

    
Notifies all registered StructuredFileListeners about deleted blocks.

Parameters:
index the index blocks were deleted at.
deletedBlocks the number of blocks which were deleted starting at index.
Throws:
IOException if reading or writing fails.
    private void fireBlocksDeleted(final long index,
        final long deletedBlocksthrows IOException
    {
        final Object[] listeners = this..getListenerList();
        for (int i = listeners.length - 2; i >= 0; i -= 2)
        {
            if (listeners[i] == StructuredFileListener.class)
            {
                ((StructuredFileListener) listeners[i + 1]).
                    blocksDeleted(indexdeletedBlocks);
            }
        }
    }
    private void readAhead(final long index,
        final long blockCountthrows IOException
    {
        final int readAhead = this.getReadAhead();
        if(this. < 0L || index < this. ||
            index > this. + this.)
        {
            final int toRead = blockCount - index < readAhead ?
                (int) (blockCount - index) : readAhead;
            final int cacheByte = this.getBlockSize() * toRead;
            int read = 0;
            int total = 0;
            this.flush();
            this.getFileOperations().
                setFilePointer(index * this.getBlockSize());
            this. = toRead - 1;
            do
            {
                read = this.getFileOperations().read(this.total,
                    cacheByte - total);
                if(read == -1)
                {
                    throw new EOFException();
                }
                else
                {
                    total += read;
                }
            } while(total < cacheByte);
            this. = index;
            Arrays.fill(this.false);
        }
    }
    private byte[] newTemporaryBuffer(final int requestedthrows IOException
    {
        final byte[] tmp;
        final long length = this.getFileOperations().getLength();
        if(requested <= 0 || requested > length)
        {
            throw new IllegalArgumentException(Integer.toString(requested));
        }
        return requested <= this..length ||
            this.getMemoryManager().getAvailableBytes() < requested
            ? this.
            : this.getMemoryManager().allocateBytes(requested);
    }
    //------------------------------------------------StructuredFileOperations--
New to GrepCode? Check out our FAQ X