/* * 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.atom; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.hypergraphdb.HGHandle; import org.hypergraphdb.HGPersistentHandle; import org.hypergraphdb.HGSearchResult; import org.hypergraphdb.HGSearchable; import org.hypergraphdb.HGSortIndex; import org.hypergraphdb.HyperGraph; import org.hypergraphdb.IncidenceSetRef; import org.hypergraphdb.LazyRef; import org.hypergraphdb.storage.BAtoBA; import org.hypergraphdb.storage.BAtoHandle; import org.hypergraphdb.type.HGAtomType; import org.hypergraphdb.type.HGCompositeType; import org.hypergraphdb.type.HGProjection; /** * <p> * The type of <code>HGRelType</code>. Even though we could have treated * <code>HGRelType</code>, that would have created different <code>RecordType</code> * which would have made it harder working purely with <code>HGRel</code>ationships * outside of Java (since one would have to get to the <code>RecordType</code> by * querying on the class name). In any case, a <code>HGRelType</code> is conceptually * not really a record... * </p> */ public class HGRelTypeConstructor implements HGSearchable<HGRelType, HGPersistentHandle>, HGCompositeType { public static final String INDEX_NAME = "hg_reltype_value_index"; private HyperGraph graph = null; private HGSortIndex<byte[], HGPersistentHandle> valueIndex = null; private Map<String, HGProjection> projections = new HashMap<String, HGProjection>(); private void initProjections() { projections.put("name", new HGProjection() { public int[] getLayoutPath() { return new int[0]; } public String getName() { return "name"; } public HGHandle getType() { return graph.getTypeSystem().getTypeHandle(String.class); } public void inject(Object atomValue, Object value) { ((HGRelType)atomValue).setName((String)value); } public Object project(Object atomValue) { return ((HGRelType)atomValue).getName(); } } ); } private static class ByteComparator implements Comparator<byte[]>, java.io.Serializable { private static final long serialVersionUID = 1L; public int compare(byte [] left, byte [] right) { return new String(left).compareTo(new String(right)); } } private final HGSortIndex<byte[], HGPersistentHandle> getIndex() { if (valueIndex == null) { valueIndex = (HGSortIndex<byte[], HGPersistentHandle>)graph.getStore().getIndex(INDEX_NAME, BAtoBA.getInstance(), BAtoHandle.getInstance(graph.getHandleFactory()), new ByteComparator(), true); } return valueIndex; } public Object make(HGPersistentHandle handle, LazyRef<HGHandle[]> targetSet, IncidenceSetRef incidenceSet) { HGAtomType sType = graph.getTypeSystem().getAtomType(String.class); String name = (String)sType.make(handle, null, null); return new HGRelType(name, targetSet.deref()); } public HGPersistentHandle store(Object instance) { HGRelType relType = (HGRelType)instance; HGAtomType sType = graph.getTypeSystem().getAtomType(String.class); HGPersistentHandle result = sType.store(relType.getName()); if (getIndex().findFirst(relType.getName().getBytes()) == null) getIndex().addEntry(relType.getName().getBytes(), result); return result; } public void release(HGPersistentHandle handle) { HGAtomType sType = graph.getTypeSystem().getAtomType(String.class); String s = (String)sType.make(handle, null, null); sType.release(handle); getIndex().removeEntry(s.getBytes(), handle); } /** * <p> * A <code>HGRelType</code> <em>X</em> subsumes a <code>HGRelType</code> <em>Y</em> * iff both have the same name and arity and each target atom of <em>X</em> subsumes * the corresponding target atom of <em>Y</em>. * </p> * <p> * In plain language this reflects the logical requirement that each instance * relationship with type <em>Y</em> be also an instance (logically) of <em>X</em>. * </p> * */ public boolean subsumes(Object general, Object specific) { HGRelType grel = (HGRelType)general; HGRelType srel = (HGRelType)specific; if (general == null || specific == null) return general == specific; if (!grel.getName().equals(srel.getName()) || grel.getArity() != srel.getArity()) return false; for (int i = 0; i < grel.getArity(); i++) { HGHandle g = grel.getTargetAt(i); HGHandle s = srel.getTargetAt(i); if (g.equals(s)) continue; else { HGAtomType gt = graph.getTypeSystem().getAtomType(g); HGAtomType st = graph.getTypeSystem().getAtomType(s); if (!gt.equals(st) || !gt.subsumes(graph.get(g), graph.get(s))) return false; } } return true; } @SuppressWarnings("unchecked") public HGSearchResult<HGPersistentHandle> find(HGRelType key) { if (key == null || key.getName() == null) return (HGSearchResult<HGPersistentHandle>)HGSearchResult.EMPTY; return getIndex().find(key.getName().getBytes()); } public Iterator<String> getDimensionNames() { return projections.keySet().iterator(); } public HGProjection getProjection(String dimensionName) { return projections.get(dimensionName); } public void setHyperGraph(HyperGraph graph) { this.graph = graph; initProjections(); } }