alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.mdr.persistence.btreeimpl.btreestorage;

import java.util.*;
import java.io.*;

import org.netbeans.mdr.persistence.*;

/** 
* A stream composed of segments stored in CachedPages.  The pages
* are pinned while members of a CachedPageInputStream.  When done with
* the stream, close it to unpin the pages.
*/
public class CachedPageInputStream extends java.io.InputStream {

    /* first page in stream */
    private PageDescriptor first;

    /* last page in stream */
    private PageDescriptor last;

    /* page currently being read from */
    private PageDescriptor currentPage;

    /* current offset in curent page */
    private int currentOffset;

    /* to support mark and reset */
    private PageDescriptor markedPage;
    private int markedOffset;

    /** Add a page to the stream
    * @param pg the page to add
    * @param offst the offset in the page where the stream data begins
    * @page len length of stream data
    */
    public void addPage(CachedPage pg, int offst, int len) {
        PageDescriptor newPage = new PageDescriptor(pg, offst, len);
        if (first == null) {
            first = last = newPage;
            currentPage = first;
            currentOffset = offst;
        }
        else {
            last.next = newPage;
            last = newPage;
        }
    }

    /** close the stream.  This unpins all of the pages from the cache.
    * @exception IOException if there is an error unpinning the pages.
    */
    public void close() throws IOException {
        try {
            unpinAll();
        }
        catch (StorageException ex) {
            // By the contract of close, we are only allowed to
            // throw IOExceptions
            StreamCorruptedException newEx = 
                new StreamCorruptedException(ex.getMessage());
            throw newEx;
        }
        finally {
            first = last = currentPage = null;
            currentOffset = 0;
            super.close();
        }
    }


    /** read a byte from the stream
    * @return The next byte in the stream, or -1 if at EOF.
    */
    public int read() {
        while (true) {
            if (currentPage == null) {
                return -1;
            }
            else if (currentOffset < currentPage.end) {
                int val = (int)currentPage.page.contents[currentOffset++];
                return (val & 0xFF);
            }
            else {
                currentPage = currentPage.next;
                if (currentPage != null)
                    currentOffset = currentPage.start;
            }
        }
    }

    /** read bytes into an array
    * @param b up to b.length bytes are read into this array
    * @return The number of bytes read.  If at EOF, -1 is returned
    */
    public int read(byte b[]) {
        return read(b, 0, b.length);
    }

    /** read bytes into an array
    * @param b up to length bytes are read into this array
    * @param offset the offset into the array at whch to start storing bytes
    * @param maximum number of bytes to read
    * @return The number of bytes read.  If at EOF, -1 is returned
    */
    public int read(byte b[], int offset, int length) {
        int left;

        int toCopy = length;
        int byteOffset = offset;

        while (true) {
            if (currentPage == null) {
                return (toCopy == length) ? -1 : (length - toCopy);
            }
            else if ((left = currentPage.end - currentOffset) > 0) {
                int size = Math.min(left, toCopy);
                System.arraycopy(currentPage.page.contents, currentOffset, 
                                 b, byteOffset, size);
                currentOffset += size;
                byteOffset += size;
                toCopy -= size;
                if (toCopy == 0) {
                    return length;
                }
            }
            else {
                currentPage = currentPage.next;
                if (currentPage != null)
                    currentOffset = currentPage.start;
            }
        }
    }

    /** this class supports mark (since it's easy)
    * @return true, since we support mark
    */
    public boolean markSupported() {
        return true;
    }

    /** mark a spot in the stream, which reset will return to
    * @param readlimit ignored
    */
    public void mark(int readlimit) {
        markedPage = currentPage;
        markedOffset = currentOffset;
    }

    /** report how many bytes are still unread
    * @return number of bytes left in stream
    */
    public int available() {
        if (currentPage == null)
            return 0;

        int total = currentPage.end - currentOffset;

        for (PageDescriptor p = currentPage.next; p != null; p = p.next) {
            total += p.end - p.start;
        }

        return total;
    }

    /** return to where mark was last called, or to the beginning if
    * mark was never called.
    */
    public void reset() {
        if (markedPage != null) {
            currentPage = markedPage;
            currentOffset = markedOffset;
        }
        else {
            currentPage = first;
            if (first != null)
                currentOffset = first.start;
            else
                currentOffset = 0;
        }
    }

    /** if the stream was never closed, unpin the pages now
    */
    protected void finalize() throws StorageException {
    	unpinAll();
    }

    /* unpin all of the pages in the array */
    private void unpinAll() throws StorageException{
        for (PageDescriptor p = first; p != null; p = p.next) {
            p.page.unpin();
        }
    }

    
    /** This class describes each page in the stream.
    */
    static class PageDescriptor {

        /** The page contianing the data */
        CachedPage page;

        /** The first byte of data in the page */
        int start;

        /** One past the last byte of data in the page */
        int end;

        /** the next page in the stream */
        PageDescriptor next;

        /** Create a new page descriptor
        * @param pg the page
        * @param offset where the stream data starts
        * @param length how mnay bytes of data the page contains
        */
        public PageDescriptor(CachedPage pg, int offset, int length) {
            page = pg;
            start = offset;
            end = offset + length;
        }
    }
}
    
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.