001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.mavibot.btree.serializer;
021
022
023import java.io.EOFException;
024import java.io.IOException;
025import java.nio.ByteBuffer;
026import java.nio.channels.FileChannel;
027
028
029/**
030 * A class used to hide the buffer read from the underlying file.
031 * 
032 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
033 */
034public class BufferHandler
035{
036    /** The channel we read bytes from */
037    private FileChannel channel;
038
039    /** The buffer containing the bytes we read from the channel */
040    private ByteBuffer buffer;
041
042
043    /**
044     * Create a new BufferHandler 
045     * @param buffer The buffer used to transfer data
046     */
047    public BufferHandler( byte[] buffer )
048    {
049        this.buffer = ByteBuffer.allocate( buffer.length );
050        this.buffer.put( buffer );
051        this.buffer.flip();
052    }
053
054
055    /**
056     * Create a new BufferHandler 
057     * @param channel The channel to read
058     * @param buffer The buffer used to transfer data
059     */
060    public BufferHandler( FileChannel channel, ByteBuffer buffer )
061    {
062        this.channel = channel;
063        this.buffer = buffer;
064
065        try
066        {
067            // Initial read
068            channel.read( buffer );
069            buffer.flip();
070        }
071        catch ( IOException ioe )
072        {
073
074        }
075    }
076
077
078    public byte[] getBuffer()
079    {
080        byte[] bytes = new byte[buffer.capacity()];
081
082        buffer.get( bytes );
083
084        return bytes;
085    }
086
087
088    /**
089     * Read a buffer containing the given number of bytes
090     * @param len The number of bytes to read
091     * @return
092     */
093    public byte[] read( int len ) throws IOException
094    {
095        byte[] result = new byte[len];
096
097        if ( len <= buffer.remaining() )
098        {
099            buffer.get( result );
100
101            return result;
102        }
103
104        int requested = len;
105        int position = 0;
106
107        while ( requested != 0 )
108        {
109            int nbRemainingRead = buffer.limit() - buffer.position();
110
111            if ( nbRemainingRead > requested )
112            {
113                buffer.get( result, position, requested );
114                break;
115            }
116            else
117            {
118                System.arraycopy( buffer.array(), buffer.position(), result, position, nbRemainingRead );
119                position += nbRemainingRead;
120            }
121
122            buffer.clear();
123
124            if ( channel != null )
125            {
126                int nbReads = channel.read( buffer );
127                buffer.flip();
128
129                if ( nbReads <= 0 )
130                {
131                    throw new EOFException();
132                }
133            }
134            else
135            {
136                throw new IOException( "Not enough bytes in the buffer" );
137            }
138
139            requested -= nbRemainingRead;
140        }
141
142        return result;
143    }
144}