/*
* 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.util.ArrayList;
import java.util.List;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.hypergraphdb.HGHandle;
import org.hypergraphdb.HGException;
import org.hypergraphdb.HGLink;
import org.hypergraphdb.HGPersistentHandle;
import org.hypergraphdb.HyperGraph;
import org.hypergraphdb.HGQuery.hg;
import org.hypergraphdb.util.AccessibleObjectCache;
/**
*
* <p>
* The <code>JavaTypeFactory</code> is used to infer HyperGraph types based on
* Java beans. Java bean classes are converted to instances of
* <code>RecordType</code> and Java bean instances to the corresponding
* <code>Record</code>s. Only properties that are both readable and writeable
* are mapped to HyperGraph <code>Slot</code>s.
* </p>
*
* @author Borislav Iordanov
*/
public class JavaTypeFactory implements JavaTypeMapper
{
protected HyperGraph graph;
static private AccessibleObjectCache accessibleObjectCache = new AccessibleObjectCache();
private ArrayList<JavaTypeMapper> mappers = new ArrayList<JavaTypeMapper>();
private JavaObjectMapper objectMapper = null;
private DefaultJavaTypeMapper defaultMapper = null;
public JavaTypeFactory()
{
mappers.add(defaultMapper = new DefaultJavaTypeMapper());
mappers.add(objectMapper = new JavaObjectMapper());
}
// public void initNonDefaultMappers()
// {
// objectMapper = new JavaObjectMapper();
// objectMapper.setHyperGraph(graph);
// mappers.add(0, objectMapper);
// }
void assign(Object bean, String property, Object value)
{
BonesOfBeans.setProperty(bean, property, value);
}
public static void assignPrivate(Class<?> clazz, Object x, String field, Object value)
{
Field f = accessibleObjectCache.getField(clazz, field);
try
{
f.set(x, value);
}
catch (IllegalAccessException ex)
{
throw new HGException(ex);
}
}
public static Object retrievePrivate(Class<?> clazz, Object x, String field)
{
Field f = accessibleObjectCache.getField(x.getClass(), field);
try
{
return f.get(x);
}
catch (IllegalAccessException ex)
{
throw new HGException(ex);
}
}
public static boolean isAbstract(Class<?> c)
{
return Modifier.isAbstract(c.getModifiers()) ||
Modifier.isInterface(c.getModifiers());
}
public static Constructor<?> findDefaultConstructor(Class<?> c)
{
for (Constructor<?> con : c.getDeclaredConstructors())
if (con.getParameterTypes().length == 0)
return con;
return null;
}
public static boolean isDefaultConstructible(Class<?> c)
{
try
{
c.getConstructor(new Class[0]);
return true;
}
catch (NoSuchMethodException ex)
{
return findDefaultConstructor(c) != null;
}
}
public static Field findDeclaredField(Class<?> c, String name) throws SecurityException
{
try
{
return c.getDeclaredField(name);
}
catch (NoSuchFieldException ex)
{
return (c.getSuperclass() == null) ? null : findDeclaredField(c.getSuperclass(), name);
}
}
public static Constructor<?> findHandleArgsConstructor(Class<?> c)
{
for (Constructor<?> con : c.getDeclaredConstructors())
{
if (con.getParameterTypes().length == 0)
continue;
boolean match = true;
for (Class<?> paramClass : con.getParameterTypes())
if (!HGHandle.class.isAssignableFrom(paramClass))
{
match = false;
break;
}
if (match)
return con;
}
return null;
}
public static boolean isLink(Class<?> c)
{
boolean b = HGLink.class.isAssignableFrom(c);
if (!b)
return false;
try
{
c.getDeclaredConstructor(new Class[] { HGHandle[].class });
return true;
}
catch (NoSuchMethodException ex)
{
return findHandleArgsConstructor(c) != null;
}
}
public static boolean isHGInstantiable(Class<?> c)
{
return !isAbstract(c) && (isDefaultConstructible(c) || isLink(c));
}
public static HGHandle getSlotHandle(HyperGraph graph, String label, HGHandle type)
{
HGHandle slotHandle = hg.findOne(graph,
hg.eq(new Slot(label,type)));
if (slotHandle == null)
return graph.add(new Slot(label, type));
else
return slotHandle;
}
static HGHandle superSlot = null;
static HGHandle getSuperSlot(HyperGraph graph)
{
if (superSlot == null)
superSlot = JavaTypeFactory.getSlotHandle(
graph,
"!super",
graph.getTypeSystem().getTypeHandle(HGPersistentHandle.class));
return superSlot;
}
public HGAtomType defineHGType(Class<?> javaClass, HGHandle typeHandle)
{
for (JavaTypeMapper m : mappers)
{
HGAtomType t = m.defineHGType(javaClass, typeHandle);
if (t != null)
return t;
}
return null;
}
public HGAtomType getJavaBinding(HGHandle typeHandle, HGAtomType hgType, Class<?> javaClass)
{
for (JavaTypeMapper m : mappers)
{
HGAtomType t = m.getJavaBinding(typeHandle, hgType, javaClass);
if (t != null)
return t;
}
return null;
}
public void setHyperGraph(HyperGraph graph)
{
this.graph = graph;
for (JavaTypeMapper m : mappers)
m.setHyperGraph(graph);
}
public DefaultJavaTypeMapper getDefaultJavaMapper()
{
return defaultMapper;
}
public JavaObjectMapper getJavaObjectMapper()
{
return objectMapper;
}
public List<JavaTypeMapper> getMappers()
{
return mappers;
}
}