/*
* 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.type;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import org.hypergraphdb.HGException;
import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGPersistentHandle;
import org.hypergraphdb.HyperGraph;
import org.hypergraphdb.IncidenceSetRef;
import org.hypergraphdb.LazyRef;
/**
* <p>
* An <code>ArrayType</code> handles fixed size arrays of values of the same
* type (i.e. having the same <code>HGAtomType</code>). Fixed size means that
* once an array is created with a given size, subsequent reads and updates
* assumes exactly that size.
* </p>
*
* <p>
* Arrays may be of size 0, or even <code>null</code>. Null arrays are
* recorded by simply storing a <code>HGHandleFactory.nullHandle</code>. All
* other arrays (including 0 sized) are recorded by storing the handle of the
* element type, then a prototypical, default constructed value for the sole
* purpose of recovering the actual Java type (we avoid storing classnames since
* they are not portable), followed by each element of the array.
* </p>
*
* @author Borislav Iordanov
*/
public class ArrayType implements HGAtomType
{
private HyperGraph graph = null;
private Constructor<?> linkConstructor = null;
private Class<?> clazz;
public ArrayType(Class<?> clazz)
{
this.clazz = clazz;
try
{
linkConstructor = clazz
.getDeclaredConstructor(new Class[] { HGHandle[].class });
}
catch (NoSuchMethodException ex)
{
}
}
public Class<?> getType()
{
return clazz;
}
public void setHyperGraph(HyperGraph hg)
{
this.graph = hg;
}
public Object make(HGPersistentHandle handle,
LazyRef<HGHandle[]> targetSet,
IncidenceSetRef incidenceSet)
{
HGPersistentHandle[] layout = graph.getStore().getLink(handle);
Object result;
if (targetSet == null || targetSet.deref().length == 0)
result = Array.newInstance(clazz, layout.length / 2);
else
{
if (linkConstructor == null)
throw new HGException(
"Unable to construct a link of type "
+ clazz.getName()
+ ", the class doesn't have a HGHandle [] based constructor.");
try
{
result = linkConstructor.newInstance(new Object[] { targetSet });
}
catch (Throwable t)
{
throw new HGException(t);
}
}
TypeUtils.setValueFor(graph, handle, result);
for (int i = 0; i < layout.length; i += 2)
{
Object current = null;
HGPersistentHandle typeHandle = layout[i];
HGPersistentHandle valueHandle = layout[i + 1];
if (!typeHandle.equals(graph.getHandleFactory().nullHandle()))
{
HGAtomType type = graph.getTypeSystem().getType(typeHandle);
current = TypeUtils.makeValue(graph, valueHandle, type);
}
((Object[])result)[i / 2] = current;
}
return result;
}
public HGPersistentHandle store(Object instance)
{
HGPersistentHandle result = TypeUtils.getNewHandleFor(graph, instance);
Object[] array = (Object[]) instance;
HGPersistentHandle[] layout = new HGPersistentHandle[array.length * 2];
int pos = 0;
for (int i = 0; i < array.length; i++)
{
Object curr = array[i];
if (curr == null)
{
layout[pos++] = graph.getHandleFactory().nullHandle();
layout[pos++] = graph.getHandleFactory().nullHandle();
} else
{
HGHandle typeHandle = graph.getTypeSystem().getTypeHandle(
curr.getClass());
layout[pos++] = graph.getPersistentHandle(typeHandle);
layout[pos++] = TypeUtils.storeValue(graph, curr, graph
.getTypeSystem().getType(typeHandle));
}
}
graph.getStore().store(result, layout);
return result;
}
public void release(HGPersistentHandle handle)
{
// TypeUtils.releaseValue(hg, handle);
HGPersistentHandle[] layout = graph.getStore().getLink(handle);
for (int i = 0; i < layout.length; i += 2)
{
HGPersistentHandle typeHandle = layout[i];
HGPersistentHandle valueHandle = layout[i + 1];
if (typeHandle.equals(graph.getHandleFactory().nullHandle()))
continue;
if (!TypeUtils.isValueReleased(graph, valueHandle))
{
HGAtomType type = graph.get(typeHandle);
TypeUtils.releaseValue(graph, type, valueHandle);
//type.release(valueHandle);
}
}
graph.getStore().removeLink(handle);
}
public boolean subsumes(Object general, Object specific)
{
return false;
}
}