/* * This file is part of the HyperGraphDB source distribution. This is copyrighted * software. For permitted uses, licensing options and redistribution, please see * the LicensingInformation file at the root level of the distribution. * * Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved. */ package org.hypergraphdb.storage; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.SortedSet; import org.hypergraphdb.HGIndex; import org.hypergraphdb.HGRandomAccessResult; import org.hypergraphdb.util.HGSortedSet; /** * * <p> * A database-backed <code>HGSortedSet</code> implementation representing the * ordered duplicate values associated with a single key. * </p> * * @author Borislav Iordanov * */ @SuppressWarnings("unchecked") public class DBKeyedSortedSet<Key, T> implements HGSortedSet<T> { private Key key; private Comparator<T> comparator = null; private HGIndex<Key, T> index = null; static <E> Comparator<E> makeComparator() { return new Comparator<E>() { public int compare(E x, E y) { return ((Comparable)x).compareTo(y); } }; } public DBKeyedSortedSet(HGIndex<Key, T> idx, Key key) { this.index = idx; this.key = key; comparator = makeComparator(); } public DBKeyedSortedSet(HGIndex<Key, T> idx, Key key, Comparator<T> comparator) { this.index = idx; this.key = key; this.comparator = comparator; } public HGRandomAccessResult<T> getSearchResult() { return index.find(key); } public Comparator<T> comparator() { return comparator; } public T first() { return index.findFirst(key); } public SortedSet<T> headSet(T toElement) { throw new UnsupportedOperationException(); } public T last() { throw new UnsupportedOperationException("No easy BerkeleyDB method for this one, need to iterate until the end - unefficient."); } public SortedSet<T> subSet(T fromElement, T toElement) { throw new UnsupportedOperationException(); } public SortedSet<T> tailSet(T fromElement) { throw new UnsupportedOperationException(); } public boolean add(T o) { if (contains(o)) return false; index.addEntry(key, o); return true; } public boolean addAll(Collection c) { boolean modified = false; for (T x : (Collection<T>)c) modified = modified || add(x); return modified; } public void clear() { index.removeAllEntries(key); } public boolean contains(Object o) { HGRandomAccessResult<T> rs = getSearchResult(); try { return rs.goTo((T)o, true) == HGRandomAccessResult.GotoResult.found; } finally { rs.close(); } } public boolean containsAll(Collection c) { HGRandomAccessResult<T> rs = getSearchResult(); try { for (T x : (Collection<T>)c) if (rs.goTo(x, true) != HGRandomAccessResult.GotoResult.found) return false; return true; } finally { rs.close(); } } public boolean isEmpty() { return first() == null; } /** * <p> * This iterator is intended for use when full iteration is performed on the set. * Otherwise, the underlying DB cursor remains open and locks DB pages forever. * </p> */ public Iterator<T> iterator() { /* final HGRandomAccessResult<T> rs = getSearchResult(); return new Iterator<T>() { boolean closed = false; public void remove() { throw new UnsupportedOperationException(); } public boolean hasNext() { return !closed && rs.hasNext(); } public T next() { T n = rs.next(); if (!rs.hasNext()) { rs.close(); closed = true; } return n; } protected void finalize() { if (!closed) rs.close(); } }; */ throw new UnsupportedOperationException("Use getSearchResult and make sure you close it."); } public boolean remove(Object o) { if (contains(o)) { index.removeEntry(key, (T)o); return true; } else return false; } public boolean removeAll(Collection c) { boolean modified = false; for (Object x : c) modified = modified || remove(x); return modified; } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } public int size() { return (int)index.count(key); } public Object[] toArray() { HGRandomAccessResult<T> rs = getSearchResult(); try { int size = size(); Object [] a = new Object[size]; for (int i = 0; i < size; i++) a[i] = rs.next(); return a; } finally { rs.close(); } } public <E> E[] toArray(E[] a) { HGRandomAccessResult<T> rs = getSearchResult(); try { int size = size(); if (a.length < size) a = (E[])java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), size); for (int i = 0; i < size; i++) a[i] = (E)rs.next(); if (a.length > size) a[size] = null; return a; } finally { rs.close(); } } }