Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  jDTAUS Core Utilities
   *  Copyright (c) 2005 Christian Schulte
   *
   *  Christian Schulte, Haldener Strasse 72, 58095 Hagen, Germany
   *  <cs@jdtaus.org> (+49 2331 3543887)
   *
   *  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.messages.DeletesBlocksMessage;
 import  org.jdtaus.core.messages.InsertsBlocksMessage;
 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.spi.Task;
 import  org.jdtaus.core.monitor.spi.TaskMonitor;

StructuredFile implementation based on FileOperations.

Pre FlushableFileOperations and its implementations this implementation performed read-ahead caching. This behaviour got changed in favour of ReadAheadFileOperations and CoalescingFileOperations which are generalized replacements for any cacheing formerly performed by this implementation. Since this class does not implement any cacheing anymore, the flush() method will write out pending changes of an underlying FlushableFileOperations implementation, if any, by calling the corresponding flush() method of that FlushableFileOperations instance.

This implementation uses task monitoring for the deleteBlocks() and insertBlocks() methods. Task monitoring is controlled by property monitoringThreshold holding the number of bytes which need to minimally be copied to enable any task monitoring during the copy operation (defaults to 5242880 - 5MB).

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

Author(s):
Christian Schulte
Version:
$Id: StructuredFileOperations.java 5034 2008-07-04 11:04:09Z schulte2005 $
See also:
CoalescingFileOperations
ReadAheadFileOperations
 
 public final class StructuredFileOperations implements StructuredFile
 {
     //--Fields------------------------------------------------------------------
 
    
Pre-allocated temporary buffer.
 
     private byte[] minimumBuffer;

    
Caches the value of property blockCount.
 
     private long cachedBlockCount = ;
 
     private static final long NO_CACHED_BLOCKCOUNT = .;

    
List for StructuredFileListeners.
 
     private final EventListenerList fileListeners = new EventListenerList();

    
Value of property blockSize as a BigDecimal.
 
     private final BigDecimal decimalBlockSize;
 
     //------------------------------------------------------------------Fields--
     //--Implementation----------------------------------------------------------
 
 // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausImplementation
     // This section is managed by jdtaus-container-mojo.
 
    
Meta-data describing the implementation.
 
     private static final Implementation META =
         ModelFactory.getModel().getModules().
        getImplementation(StructuredFileOperations.class.getName());
// </editor-fold>//GEN-END:jdtausImplementation
    //----------------------------------------------------------Implementation--
    //--Constructors------------------------------------------------------------
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausConstructors
    // This section is managed by jdtaus-container-mojo.

    
Initializes the properties of the instance.

Parameters:
meta the property values to initialize the instance with.
Throws:
NullPointerException if meta is null.
    private void initializeProperties(final Properties meta)
    {
        Property p;
        if(meta == null)
        {
            throw new NullPointerException("meta");
        }
        p = meta.getProperty("monitoringThreshold");
        this. = ((java.lang.Integerp.getValue()).intValue();
        p = meta.getProperty("minBufferedBlocks");
        this. = ((java.lang.Integerp.getValue()).intValue();
        p = meta.getProperty("blockSize");
        this. = ((java.lang.Integerp.getValue()).intValue();
    }
// </editor-fold>//GEN-END:jdtausConstructors
    //------------------------------------------------------------Constructors--
    //--Dependencies------------------------------------------------------------
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
    // This section is managed by jdtaus-container-mojo.

    
Configured TaskMonitor implementation.
    private transient TaskMonitor dTaskMonitor;

    
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 dMemoryManager;

    
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;
    }
// </editor-fold>//GEN-END:jdtausDependencies
    //------------------------------------------------------------Dependencies--
    //--Properties--------------------------------------------------------------
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
    // This section is managed by jdtaus-container-mojo.

    
Property monitoringThreshold.

Serial:
    private int pMonitoringThreshold;

    
Gets the value of property monitoringThreshold.

Returns:
the value of property monitoringThreshold.
    public int getMonitoringThreshold()
    {
        return this.;
    }

    
Property minBufferedBlocks.

Serial:
    private int pMinBufferedBlocks;

    
Gets the value of property minBufferedBlocks.

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

    
Property blockSize.

Serial:
    private int pBlockSize;

    
Gets the value of property blockSize.

Returns:
the value of property blockSize.
    public int getBlockSize()
    {
        return this.;
    }
// </editor-fold>//GEN-END:jdtausProperties
    //--------------------------------------------------------------Properties--
    //--StructuredFile----------------------------------------------------------
    public long getBlockCount() throws IOException
    {
        this.assertNotClosed();
        if ( this. ==  )
        {
            this. = new BigDecimal(
                this.getFileOperations().getLength() ).divide(
                this.. ).
                longValue();
        // TODO JDK 1.5 longValueExact()
        }
        return this.;
    }
    public void deleteBlocksfinal long index,
                               final long count ) throws IOException
    {
        final long blockCount = this.getBlockCount();
        // Preconditions.
        if ( index < 0L || index > blockCount - count )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) index );
        }
        if ( count <= 0 || count > blockCount - index )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) count );
        }
        this.assertNotClosed();
        this.deleteBlocksImplindexcountblockCount );
    }
    private void deleteBlocksImplfinal long indexfinal long count,
                                    final long blockCount ) throws IOException
    {
        final long block = index + count;
        final Task task = new Task();
        long toMoveByte = ( blockCount - block ) * this.getBlockSize();
        long readPos = block * this.getBlockSize();
        long writePos = index * this.getBlockSize();
        long progress = 0L;
        long progressDivisor = 1L;
        long maxProgress = toMoveByte;
        // Clear the cached block count.
        this. = ;
        // No blocks are following the ones to remove.
        if ( toMoveByte == 0L )
        {
            this.getFileOperations().setLength( this.getFileOperations().
                                                getLength() - count *
                                                this.getBlockSize() );
            this.fireBlocksDeletedindexcount );
            return;
        }
        final byte[] buf = this.newTemporaryBuffer(
            toMoveByte > .
            ? .
            : ( int ) toMoveByte );
        while ( maxProgress > . )
        {
            maxProgress /= 2L;
            progressDivisor *= 2L;
        }
        task.setIndeterminate( false );
        task.setCancelable( false );
        task.setMinimum( 0 );
        task.setMaximum( ( int ) maxProgress );
        task.setProgress( ( int ) progress );
        task.setDescription( new DeletesBlocksMessage() );
        final boolean monitoring = toMoveByte > this.getMonitoringThreshold();
        if ( monitoring )
        {
            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
                    ? ( int ) toMoveByte
                    : buf.length;
                int read = 0;
                int total = 0;
                do
                {
                    read = this.getFileOperations().
                        read( buftotallen - total );
                    assert read != FileOperations.EOF :
                        "Unexpected end of file.";
                    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;
                progress += len;
                task.setProgress( ( int ) ( progress / progressDivisor ) );
            }
            // Truncate the file.
            this.getFileOperations().setLength( this.getFileOperations().
                                                getLength() - count *
                                                this.getBlockSize() );
            this.fireBlocksDeletedindexcount );
        }
        finally
        {
            if ( monitoring )
            {
                this.getTaskMonitor().finish( task );
            }
        }
    }
    public void insertBlocksfinal long index,
                               final long count ) throws IOException
    {
        final long blockCount = this.getBlockCount();
        // Preconditions.
        if ( index < 0L || index > blockCount )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) index );
        }
        if ( count <= 0L || count > . - blockCount )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) count );
        }
        this.assertNotClosed();
        this.insertBlocksImplindexcountblockCount );
    }
    private void insertBlocksImplfinal long indexfinal long count,
                                    final long blockCount ) throws IOException
    {
        final Task task = new Task();
        long toMoveByte = ( blockCount - index ) * this.getBlockSize();
        long readPos = blockCount * this.getBlockSize();
        long writePos = readPos + count * this.getBlockSize();
        long progress = 0L;
        long progressDivisor = 1L;
        long maxProgress = toMoveByte;
        // Clear the cached block count.
        this. = ;
        // 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.fireBlocksInsertedindexcount );
            return;
        }
        final byte[] buf = this.newTemporaryBuffer(
            toMoveByte > .
            ? .
            : ( int ) toMoveByte );
        while ( maxProgress > . )
        {
            maxProgress /= 2L;
            progressDivisor *= 2L;
        }
        task.setIndeterminate( false );
        task.setCancelable( false );
        task.setMinimum( 0 );
        task.setMaximum( ( int ) maxProgress );
        task.setProgress( ( int ) progress );
        task.setDescription( new InsertsBlocksMessage() );
        final boolean monitoring = toMoveByte > this.getMonitoringThreshold();
        if ( monitoring )
        {
            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
                    ? ( int ) toMoveByte
                    : buf.length;
                readPos -= moveLen;
                writePos -= moveLen;
                this.getFileOperations().setFilePointer( readPos );
                int read = 0;
                int total = 0;
                do
                {
                    read = this.getFileOperations().
                        read( buftotalmoveLen - total );
                    assert read != FileOperations.EOF :
                        "Unexpected end of file.";
                    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;
                progress += moveLen;
                task.setProgress( ( int ) ( progress / progressDivisor ) );
            }
            this.fireBlocksInsertedindexcount );
        }
        finally
        {
            if ( monitoring )
            {
                this.getTaskMonitor().finish( task );
            }
        }
    }
    public void readBlockfinal long blockfinal int off,
                            final byte[] buf ) throws IOException
    {
        this.readBlockblockoffbuf, 0, buf.length );
    }
    public void readBlockfinal long blockfinal int offfinal byte[] buf,
                            final int indexfinal int length )
        throws IOException
    {
        this.assertValidArgumentsblockoffbufindexlength );
        this.assertNotClosed();
        int totalRead = 0;
        int toRead = length;
        this.getFileOperations().setFilePointer(
            block * this.getBlockSize() + off );
        do
        {
            final int read = this.getFileOperations().
                read( bufindex + totalReadtoRead );
            assert read != FileOperations.EOF :
                "Unexpected end of file.";
            totalRead += read;
            toRead -= read;
        }
        while ( totalRead < length );
    }
    public void writeBlockfinal long blockfinal int off,
                             final byte[] buf ) throws IOException
    {
        this.writeBlockblockoffbuf, 0, buf.length );
    }
    public void writeBlockfinal long blockfinal int off,
                             final byte[] buf,
                             final int indexfinal int length )
        throws IOException
    {
        this.assertValidArgumentsblockoffbufindexlength );
        this.assertNotClosed();
        this.getFileOperations().setFilePointer(
            block * this.getBlockSize() + off );
        this.getFileOperations().write( bufindexlength );
    }

    
Flushes the instance and closes the FileOperations implementation backing the instance.

Throws:
IOException if closing the FileOperations implementation backing the instance fails, or if the instance already is closed.
    public void close() throws IOException
    {
        this.assertNotClosed();
        this.flush();
        this.getFileOperations().close();
        this. = true;
    }
    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------------------------------------------------

    
FileOperations backing the instance.
    private FileOperations fileOperations;

    
Flags the instance as beeing closed.
    private boolean closed;

    
Creates a new StructuredFileOperations instance taking the size of one block in byte and the FileOperations operations are to be performed with.

Parameters:
blockSize Number of bytes per block.
fileOperations FileOperations implementation to operate on.
Throws:
NullPointerException if fileOperations is null.
PropertyException if blockSize is negative or zero.
IllegalArgumentException if blockSize is incompatible with the length of fileOperations.
IOException if getting the length from the fileOperations fails.
    public StructuredFileOperationsfinal int blockSize,
                                      final FileOperations fileOperations )
        throws IOException
    {
        super();
        this.initializeProperties.getProperties() );
        this. = blockSize;
        this.assertValidProperties();
        if ( fileOperations == null )
        {
            throw new NullPointerException"fileOperations" );
        }
        this. = fileOperations;
        final int minBufferedBlocks = this.getMinBufferedBlocks();
        this. = this.getMemoryManager().
            allocateBytes( minBufferedBlocks * blockSize );
        this.assertValidFileLength();
        this. = new BigDecimalblockSize );
    }

    
Creates a new StructuredFileOperations instance taking the size of one block in byte, task monitoring configuration and the FileOperations operations are to be performed with.

Parameters:
blockSize Number of bytes per block.
monitoringThreshold the mininum number of bytes to copy to start any task monitoring.
fileOperations FileOperations implementation to operate on.
Throws:
NullPointerException if fileOperations is null.
PropertyException if either blockSize or monitoringTeshold is negative or zero.
IllegalArgumentException if blockSize is incompatible with the length of fileOperations.
IOException if getting the length from the fileOperations fails.
    public StructuredFileOperationsfinal int blockSize,
                                      final int monitoringThreshold,
                                      final FileOperations fileOperations )
        throws IOException
    {
        super();
        this.initializeProperties.getProperties() );
        this. = blockSize;
        this. = monitoringThreshold;
        this.assertValidProperties();
        if ( fileOperations == null )
        {
            throw new NullPointerException"fileOperations" );
        }
        this. = fileOperations;
        final int minBufferedBlocks = this.getMinBufferedBlocks();
        this. = this.getMemoryManager().
            allocateBytes( minBufferedBlocks * blockSize );
        this.assertValidFileLength();
        this. = new BigDecimalblockSize );
    }

    
Gets the FileOperations implementation operations are performed with.

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

    
Calls the flush() method of an underlying FlushableFileOperations instance, if any.

Throws:
IOException if reading or writing fails.
    public void flush() throws IOException
    {
        this.assertNotClosed();
        if ( this.getFileOperations() instanceof FlushableFileOperations )
        {
            ( ( FlushableFileOperations ) this.getFileOperations() ).flush();
        }
    }

    
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() minus {@code off.
    private void assertValidArgumentsfinal long blockfinal int off,
                                        final byte[] buffinal int index,
                                        final int length ) throws
    {
        final long blockCount = this.getBlockCount();
        if ( buf == null )
        {
            throw new NullPointerException"buf" );
        }
        if ( block < 0 || block >= blockCount )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) block );
        }
        if ( off < 0 || off >= this.getBlockSize() )
        {
            throw new ArrayIndexOutOfBoundsException( ( int ) off );
        }
        if ( index < 0 || index >= buf.length )
        {
            throw new ArrayIndexOutOfBoundsExceptionindex );
        }
        if ( length < 0L || length > buf.length - index ||
            length > this.getBlockSize() - off )
        {
            throw new ArrayIndexOutOfBoundsExceptionlength );
        }
    }

    
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 blockSize = this.getBlockSize();
        final int monitoringThreshold = this.getMonitoringThreshold();
        // minBufferedBlocks must be a positive integer.
        if ( !( minBufferedBlocks > 0 ) )
        {
            throw new PropertyException(
                "minBufferedBlocks",
                Integer.toStringminBufferedBlocks ) );
        }
        // blockSize must be a positive integer.
        if ( !( blockSize > 0 ) )
        {
            throw new PropertyException( "blockSize",
                                         Integer.toStringblockSize ) );
        }
        // monitoringThreshold must be a positive integer.
        if ( !( monitoringThreshold > 0 ) )
        {
            throw new PropertyException(
                "monitoringThreshold",
                Integer.toStringmonitoringThreshold ) );
        }
    }

    
Checks that the instance is not closed.

Throws:
IOException if the instance is closed.
    private void assertNotClosed() throws IOException
    {
        if ( this. )
        {
            throw new IOException( StructuredFileOperationsBundle.getInstance().
                                   getAlreadyClosedText( Locale.getDefault() ) );
        }
    }

    
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 indexfinal long insertedBlocks ) throws 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 indexfinal long deletedBlocks ) throws 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 byte[] newTemporaryBufferfinal int requested ) throws IOException
    {
        final byte[] tmp;
        final long length = this.getFileOperations().getLength();
        if ( requested <= 0 || requested > length )
        {
            throw new IllegalArgumentException( Integer.toStringrequested ) );
        }
        return requested <= this..length ||
            this.getMemoryManager().getAvailableBytes() < requested
            ? this.
            : this.getMemoryManager().allocateBytes( requested );
    }
    //------------------------------------------------StructuredFileOperations--
New to GrepCode? Check out our FAQ X