/*
* 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.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGPersistentHandle;
import org.hypergraphdb.HGStore;
import org.hypergraphdb.util.Pair;
/**
* <p>
* A {@link StorageGraph} bound to a {@link HGStore}. It's based on a set of root handles
* and its iterator will traverse the primitive storage graph starting from those roots.
* </p>
*
* @author Borislav Iordanov
*
*/
public class HGStoreSubgraph implements StorageGraph
{
private Set<HGPersistentHandle> roots;
private HGStore store;
/**
* <p>
* Construct a new {@link HGStore} based {@link StorageGraph}
* </p>
* @param root A single root, starting point of the storage graph.
* @param store The backing store instance.
*/
public HGStoreSubgraph(HGHandle root, HGStore store)
{
this.roots = new HashSet<HGPersistentHandle>();
this.roots.add(root.getPersistent());
this.store = store;
}
/**
* <p>
* Construct a new {@link HGStore} based {@link StorageGraph}
* with multiple roots.
* </p>
* @param root A single root, starting point of the storage graph.
* @param store The backing store instance.
*/
public HGStoreSubgraph(Set<HGHandle> roots, HGStore store)
{
this.roots = new HashSet<HGPersistentHandle>();
for (HGHandle root : roots)
this.roots.add(root.getPersistent());
this.store = store;
}
public byte[] getData(HGPersistentHandle handle)
{
return store.getData(handle);
}
public HGPersistentHandle[] getLink(HGPersistentHandle handle)
{
return store.getLink(handle);
}
public HGPersistentHandle store(HGPersistentHandle handle,
HGPersistentHandle[] link)
{
return store.store(handle, link);
}
public HGPersistentHandle store(HGPersistentHandle handle, byte[] data)
{
return store.store(handle, data);
}
public Set<HGPersistentHandle> getRoots()
{
return roots;
}
public Iterator<Pair<HGPersistentHandle, Object>> iterator()
{
return new SubgraphIterator();
}
private class SubgraphIterator implements Iterator<Pair<HGPersistentHandle, Object>>
{
LinkedList<HGPersistentHandle> remaining = new LinkedList<HGPersistentHandle>();
HashSet<HGPersistentHandle> visited = new HashSet<HGPersistentHandle>();
public SubgraphIterator()
{
for (HGPersistentHandle root : roots)
remaining.addLast(root);
//TODO some UUIDs should not be visited?
visited.add(store.getTransactionManager().getHyperGraph().getHandleFactory().nullHandle());
}
public boolean hasNext()
{
return !remaining.isEmpty();
}
public Pair<HGPersistentHandle, Object> next()
{
Pair<HGPersistentHandle, Object> result = null;
HGPersistentHandle h = remaining.removeFirst();
HGPersistentHandle[] link = store.getLink(h);
if (link == null)
{
byte [] data = store.getData(h);
//TODO throw exception for missing data
if (data != null)
{
visited.add(h);
result = new Pair<HGPersistentHandle, Object>(h, data);
}
else
System.err.println("oops, handle not in store " + h);
}
else
{
visited.add(h);
for (HGPersistentHandle x : link)
{
// do we want to prevent null from being returned...it's legit for some
if (!visited.contains(x) /* && (store.getData(x) != null || store.getLink(x) != null) */ )
remaining.addLast(x);
}
result = new Pair<HGPersistentHandle, Object>(h, link);
}
return result;
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
}