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

package org.netbeans.mdr.persistence.btreeimpl.btreeindex;

/*
 *                 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.
 */
import org.netbeans.mdr.persistence.*;
import java.util.*;
import java.text.*;

/**
 * List view of the values associated with a single key in a MultivaluedBtree.
 *
 * @author	Dana Bergen
 * @version	1.0
 */
/*
 * Unlike BtreeIterator, we don't bother to unpin pages here.  We can do this
 * because BtreeListByKey is only used with BtreeMDRSource-based btrees, 
 * for which unpin is a no-op.
 */
public class BtreeListByKey extends AbstractSequentialList {

    private MultivaluedBtree btree;
    private byte[] key;
    private Object objectKey;    
    private int listModCounter = 0;
    
    BtreeListByKey(MultivaluedBtree btree, Object key) throws StorageException {

        this.btree = btree;
        this.objectKey = key;
        this.key = btree.keyInfo.toBuffer(key);
	if (this.key == null) {
	    throw new StorageBadRequestException(
	    	MessageFormat.format(
		"Invalid key type for this index: {0} received, {1} expected",
			new Object[] {
			    key.getClass().getName(),
			    btree.keyInfo.typeName()} ));
	}
    }
    
    public int size() {        
        BtreeListByKeyIterator iterator = new BtreeListByKeyIterator(0, null);
        while (iterator.moveForward()) {}
	return iterator.previousIndex();
    }
    
    public boolean isEmpty() {
        return !listIterator(0).hasNext();
    }
    
    public boolean add(Object o) {
        ListIterator it = listIterator();
        while (it.hasNext()) it.next();
        it.add(o);
        return true;
    }
    
    public boolean addAll(Collection c) {
        boolean result = false;
        ListIterator it = listIterator();
        Iterator cit;
        while (it.hasNext()) it.next();
        for (cit = c.iterator(); cit.hasNext();) {
            try {
                it.add(cit.next());
                result = true;
            } catch (RuntimeStorageException e) {
            }
        }
        return result;
    }

    public void increaseModCount () {
        listModCounter++;
    }

    public int hashCode() {
        return objectKey.hashCode();
    }

    public boolean equals(Object o) {
        if (o instanceof BtreeListByKey)
            return ((BtreeListByKey) o).objectKey.equals(objectKey);
        if (o instanceof Key)
            return ((Key) o).objectKey.equals(objectKey);
        return false;
    }
    
    public ListIterator listIterator(int index) {
        return new BtreeListByKeyIterator(index, null);
    }
    
    ListIterator listIterator (int index, SinglevaluedIndex repos) {
        return new BtreeListByKeyIterator(index, repos);
    }
    
    // Iterator ..................................................................
    
    public class BtreeListByKeyIterator extends Object
					    implements ListIterator {

        /* [TODO] Performance of next/previous operations should be improved by 
         * implementing live scan position holder that reflects all changes done over 
         * the index (for now, scan position relocations are required if the index is 
         * modifed outside the iterator and btree pages storing data related to the 
         * iterator are affected).
         */
                                                
	/* Btree scan position */
	private SearchResult current;
        /* Btree scan position of the leftmost entry matching the key */
        private SearchResult first;
	/* Index of the last item returned */
	private int index;
	private boolean empty;
	private int modCount;
        private SinglevaluedIndex repos;
        private boolean itemAvailable = false;
        /* true if the available item has been retrieved by next operation */
        private boolean retrievedByNext = false;
	
	BtreeListByKeyIterator(int startIndex, SinglevaluedIndex repos) 
					throws IndexOutOfBoundsException {
	    try {
                this.repos = repos;
		btree.beginRead();
		modCount = listModCounter;
		index = -1;
		current = btree.getLocation(key);
                first = new SearchResult (current);                
		current.entryNum--;                
		if (!current.matched) {                    
		    empty = true;
		}
                
                if (startIndex < 0) throw new IndexOutOfBoundsException();

		for (int i = 0; i < startIndex; i++) {
	    	    if (!moveForward()) {
	                throw new IndexOutOfBoundsException();
	    	    }
		}

	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endRead();
	    }
	}

	public Object next() throws NoSuchElementException {
	    if (!moveForward()) {
	        throw new NoSuchElementException();
	    }            
            itemAvailable = true;
            retrievedByNext = true;
	    return getCurrentItem();
	}

	public Object previous() throws NoSuchElementException {

	    Object item;

	    if (index == -1) {
	        throw new NoSuchElementException();
	    }
	    item = getCurrentItem();
	    moveBackward();
            itemAvailable = true;
            retrievedByNext = false;            
	    return item;
	}

	public boolean hasNext() {    
	    try {
	        btree.beginRead();
		checkModCount();
                locateCurrentItem();
	        return BtreePage.hasNext(key, current);
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endRead();
	    }
	}

	public boolean hasPrevious() {
	    return (index >= 0);
	}

	private boolean moveForward() {

	    try {
	        btree.beginRead();
		checkModCount();
                locateCurrentItem();
	        BtreePage.getNext(key, current);
	        index++;
		return current.matched;
	    } catch (StorageException e) {
                
                e.printStackTrace ();
                
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endRead();
	    }
	}

	private void moveBackward() {
	    try {
	        btree.beginRead();
		checkModCount();
                locateCurrentItem();
                int tempEntryNum = current.entryNum;
	        BtreePage.getPrevious(key, current);
                if (!current.matched && (current.entryNum == tempEntryNum))
                    current.entryNum--;
	        index--;
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endRead();
	    }
	}

	private Object getCurrentItem() {
	    Object result;

	    try {
		btree.beginRead();
		checkModCount();
                locateCurrentItem();
                if (repos != null) {
                    result = btree.dataInfo.objectFromBuffer(
                		    current.page.getData(current.entryNum), repos);
                }
                else {
		    result = btree.dataInfo.fromBuffer(
                		    current.page.getData(current.entryNum));
                }
		return result;
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endRead();
	    }
	}
        
	public int nextIndex() {
	    return index + 1;
	}

	public int previousIndex() {
	    return index;
	}

	private void checkModCount() {
	    if (listModCounter != modCount) {
	        throw new ConcurrentModificationException("Index " 
			+ btree.getName() 
                        + ", key "
                        + objectKey
			+ " has been modified since iterator was created.");
	    }
	}
                
	public void remove() {
            if (!itemAvailable)
                throw new IllegalStateException ();
            checkModCount ();
	    removeItem ();
            itemAvailable = false;
            if (retrievedByNext)
                index--;
            listModCounter++;
            modCount = listModCounter;
	}

	public void set(Object o) {
            if (!itemAvailable)
                throw new IllegalStateException ();
            checkModCount ();
            setItem (o);
            listModCounter++;
            modCount = listModCounter;
	}

	public void add(Object o) {
            checkModCount ();
	    addItem (o);
            itemAvailable = false;            
            index++;
            listModCounter++;
            modCount = listModCounter;
	}
        
        private void setItem(Object o) {            
	    try {                                
		btree.beginWrite();
                locateCurrentItem();
                BtreePage.BtreeEntry entry = new BtreePage.BtreeEntry (key, btree.dataInfo.toBuffer (o));
                if (current.page instanceof ShrinkablePage) {
                    BtreePage root = btree.pageSource.getPage(btree.rootPageId, btree);
                    root.put(key, btree.dataInfo.toBuffer (o), Btree.REPLACE, index, current);
                    btree.pageSource.unpinPage(root);
                } else {                
                    // we can call replace directly on a page (instead of tree) to achieve a better performance
                    current.page.replace(entry, current.entryNum, null);
                }
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endWrite();
	    }
	}
        
        private void removeItem() {            
	    try {
		btree.beginWrite();                
                locateCurrentItem();
                SearchResult temp = new SearchResult (current);
                if (retrievedByNext) {
                    BtreePage.getPrevious(key, current);
                    if (!current.matched && (current.entryNum == temp.entryNum))
                        current.entryNum--;
                } else {
                    BtreePage.getNext(key, temp);
                }
                // delete does not merge pages, thus we can perform it directly on the page
                temp.page.delete(temp.entryNum, temp.entryNum);                
                if ((retrievedByNext && (index == 0)) || (!retrievedByNext && (index == -1))) {
                    first = new SearchResult(current);
                    BtreePage.getNext(key, first);
                }
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endWrite();
	    }
	}
        
        private void addItem(Object o) {
	    try {                
		btree.beginWrite();
                locateCurrentItem();
                BtreePage root = btree.pageSource.getPage(btree.rootPageId, btree);
                root.put(key, btree.dataInfo.toBuffer (o), Btree.ADD, index + 1, current);
                btree.pageSource.unpinPage(root);
                if (index == -1) {
                    first = new SearchResult(current);
                }
	        // BtreePage.getNext(key, current);
	    } catch (StorageException e) {
	        throw new RuntimeStorageException(e);
	    } finally {
	        btree.endWrite();
	    }
	}
        
        private void locateCurrentItem() throws StorageException {
            SearchResult res = first.page.searchPage(key, first.entryNum);
            if ((first.entryNum != res.entryNum) || (first.page != res.page)) {
                first = res;
                current = new SearchResult (first);
                if (index == -1) {
                    current.entryNum--;
                } else {
                    first.page.findNth(current, key, index, false);
                }
            } else {
                if ((index > -1) && (current.page.compare(key, current.entryNum) != EntryTypeInfo.EQUAL)) {
                    current = new SearchResult (first);
                    first.page.findNth(current, key, index, false);
                }
            }
        }
        
    } // BtreeListByKeyIterator class
    
    /**
     * This class is used to query for BtreeListByKey instances in hashtables.
     */
    static class Key {
        
        private Object objectKey;
        
        Key (Object key) {
            objectKey = key;
        }
        
        public int hashCode() {
            return objectKey.hashCode();
        }

        public boolean equals(Object o) {
            if (o instanceof BtreeListByKey)
                return ((BtreeListByKey) o).objectKey.equals(objectKey);
            if (o instanceof Key)
                return ((Key) o).objectKey.equals(objectKey);
            return false;
        }
        
    } // Key class
    
}
... 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.