/* * 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.Constructor; import java.util.Stack; import org.hypergraphdb.HGException; import org.hypergraphdb.HGHandle; import org.hypergraphdb.HGPersistentHandle; import org.hypergraphdb.IncidenceSetRef; import org.hypergraphdb.LazyRef; import org.hypergraphdb.atom.HGAtomRef; import org.hypergraphdb.util.Pair; public class JavaObjectBinding extends JavaAbstractBinding { private Constructor<?> linkConstructor = null; public JavaObjectBinding(HGHandle typeHandle, RecordType hgType, Class<?> clazz) { super(typeHandle, hgType, clazz); try { linkConstructor = javaClass.getDeclaredConstructor(new Class[] {HGHandle[].class} ); } catch (NoSuchMethodException ex) { } } private void assignFields(HGPersistentHandle valueHandle, Object instance) { HGHandle superSlot = JavaTypeFactory.getSuperSlot(graph); RecordType hgType = (RecordType)this.hgType; Class<?> clazz = javaClass; while (true) { Record record = (Record)hgType.make(valueHandle, null, null); HGPersistentHandle ss = null; for (HGHandle slotHandle : hgType.getSlots()) { Slot slot = (Slot)graph.get(slotHandle); if (slotHandle.equals(superSlot)) { ss = (HGPersistentHandle)record.get(slot); continue; } Object value = record.get(slot); if (value != null && hgType.getReferenceMode(slotHandle) != null) value = graph.get(((HGAtomRef)value).getReferent()); JavaTypeFactory.assignPrivate(clazz, instance, slot.getLabel(), value); } if (ss != null) { clazz = clazz.getSuperclass(); JavaAbstractBinding superType = (JavaAbstractBinding)graph.getTypeSystem().getAtomType(clazz); hgType = (RecordType)superType.getHGType(); valueHandle = ss; } else break; } } public Object make(HGPersistentHandle handle, LazyRef<HGHandle[]> targetSet, IncidenceSetRef incidenceSet) { Object result = null; try { if (targetSet != null && targetSet.deref().length > 0) if (linkConstructor != null) result = linkConstructor.newInstance(new Object[] { targetSet.deref() }); else throw new RuntimeException("Can't construct link with Java type " + javaClass.getName() + " please include a (HGHandle [] ) constructor."); else result = javaClass.newInstance(); TypeUtils.setValueFor(graph, handle, result); assignFields(handle, result); } catch (InstantiationException ex) { throw new HGException("Unable to instantiate bean of type '" + javaClass.getName() + "', make sure that bean has a default constructor declared."); } catch (Throwable t) { throw new HGException("JavaTypeBinding.make: " + t.toString(), t); } return result; } public HGPersistentHandle store(final Object instance) { HGPersistentHandle result = TypeUtils.getHandleFor(graph, instance); if (result == null) { HGHandle superSlotHandle = JavaTypeFactory.getSuperSlot(graph); Slot superSlot = graph.get(superSlotHandle); Class<?> clazz = javaClass; RecordType recordType = (RecordType)hgType; Record record = new BeanRecord(typeHandle, instance); Stack<Pair<RecordType, Record>> superList = new Stack<Pair<RecordType, Record>>(); while (true) { superList.push(new Pair<RecordType, Record>(recordType, record)); boolean has_super = false; for (HGHandle slotHandle : recordType.getSlots()) { if (slotHandle.equals(superSlotHandle)) { has_super = true; continue; } else { Slot slot = (Slot)graph.get(slotHandle); // Normal field declared at the level of instances' class. Object value = JavaTypeFactory.retrievePrivate(clazz, instance, slot.getLabel()); HGAtomRef.Mode refMode = recordType.getReferenceMode(slotHandle); if (refMode != null && value != null) { HGHandle valueAtomHandle = graph.getHandle(value); if (valueAtomHandle == null) { HGAtomType valueType = (HGAtomType)graph.get(slot.getValueType()); valueAtomHandle = graph.getPersistentHandle( graph.add(value, valueType instanceof HGAbstractType ? graph.getTypeSystem().getTypeHandle(value.getClass()) : slot.getValueType())); } value = new HGAtomRef(valueAtomHandle, refMode); } record.set(slot, value); } } if (has_super) { clazz = clazz.getSuperclass(); HGHandle superTypeHandle = graph.getTypeSystem().getTypeHandle(clazz); JavaAbstractBinding superType = graph.get(superTypeHandle); recordType = (RecordType)superType.getHGType(); record = new Record(superTypeHandle); } else break; } while (!superList.isEmpty()) { Pair<RecordType, Record> curr = superList.pop(); if (result != null) curr.getSecond().set(superSlot, result); result = curr.getFirst().store(curr.getSecond()); } } return result; } public void release(HGPersistentHandle handle) { Record rec = (Record)hgType.make(handle, null, null); HGPersistentHandle parent = (HGPersistentHandle) rec.get(new Slot("!super", graph.getTypeSystem().getTypeHandle(HGPersistentHandle.class))); if (parent != null) { HGAtomType superType = graph.getTypeSystem().getAtomType(javaClass.getSuperclass()); superType.release(parent); } hgType.release(handle); } static class BeanRecord extends Record implements TypeUtils.WrappedRuntimeInstance { Object bean; BeanRecord(HGHandle h, Object bean) { super(h); this.bean = bean;} public Object getRealInstance() { return bean; } } }