/* * 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.query; import org.hypergraphdb.HGException; import org.hypergraphdb.HGHandle; import org.hypergraphdb.HGPersistentHandle; import org.hypergraphdb.HyperGraph; import org.hypergraphdb.HGLink; import org.hypergraphdb.HGQuery.hg; import org.hypergraphdb.util.Ref; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * <p> * A <code>LinkCondition</code> constraints the query result set to links * pointing to a target set of atoms. The target set is specified when * the condition is constructed through an array of <code>HGHandle</code>s. * </p> * * @author Borislav Iordanov */ public class LinkCondition implements HGQueryCondition, HGAtomPredicate { private HashSet<Ref<HGHandle>> targetSet = null; public LinkCondition() { } public LinkCondition(HGLink link) { targetSet = new HashSet<Ref<HGHandle>>(); for (int i = 0; i < link.getArity(); i++) targetSet.add(hg.constant(link.getTargetAt(i))); } public LinkCondition(HGHandle...targets) { if (targets == null) throw new HGException("LinkCondition instantiated with a null target set."); this.targetSet = new HashSet<Ref<HGHandle>>(); for (int i = 0; i < targets.length; i++) targetSet.add(hg.constant(targets[i])); } public LinkCondition(Ref<HGHandle>...targets) { this.targetSet = new HashSet<Ref<HGHandle>>(); for (int i = 0; i < targets.length; i++) targetSet.add(targets[i]); } public LinkCondition(Collection<HGHandle> targets) { if (targets == null) throw new HGException("LinkCondition instantiated with a null target set."); this.targetSet = new HashSet<Ref<HGHandle>>(); for (HGHandle h : targets) targetSet.add(hg.constant(h)); } public boolean contains(HGHandle h) { for (Ref<HGHandle> r : targetSet) if (h.equals(r.get())) return true; return false; } public Set<Ref<HGHandle>> targets() { return targetSet; } public Set<Ref<HGHandle>> getTargetSet() { return targetSet; } public void setTargetSet(HashSet<Ref<HGHandle>> targetSet) { this.targetSet = targetSet; } /** * <p>Return <code>true</code> if <code>handle</code> points to a link whose * target set is a superset of this condition's <code>targetSet</code>.</p> */ public boolean satisfies(HyperGraph graph, HGHandle handle) { int count = 0; // Since we have a set of references here, a simple 'contains' check won't work // so we need to loop through the target to check for each element of the link // under consideration. This is probably fast enough for small sets, but for larger // sets it may be performance issue. One option if the build a set of handles // if targetSet is large, each time satisfies is called. For this to be justified, // targetSet has to be especially large, say > 100. So far, I have never seen // a case like this. // If the atom corresponding to 'handle' is already in the cache, there // is no point fetching it from permanent storage. Otherwise, there's no point // caching the actual atom... if (graph.isLoaded(handle)) { Object atom = graph.get(handle); if (! (atom instanceof HGLink)) return false; HGLink link = (HGLink)atom; for (int i = 0; i < link.getArity(); i++) if (contains(link.getTargetAt(i))) count++; } else { HGPersistentHandle [] A = graph.getStore().getLink(handle.getPersistent()); // TODO: this assumes that there are no duplicates in A. Not sure whether // it should be forbidden in HyperGraph for a link to contains duplicates. // Surely, it doesn't make sense for unordered links - they are just sets. // However, ordered ones might be tricky since they are essentially lists // (<=> sets of [position, element] pairs). for (int i = 2; i < A.length; i++) if (contains(A[i])) count++; } return count == targetSet.size(); } public int hashCode() { return targetSet.hashCode(); } public boolean equals(Object x) { if (! (x instanceof LinkCondition)) return false; else return ((LinkCondition)x).targetSet.equals(targetSet); } public String toString() { StringBuffer result = new StringBuffer("links("); for (Iterator<Ref<HGHandle>> i = targetSet.iterator(); i.hasNext(); ) { result.append(i.next().get().toString()); if (i.hasNext()) result.append(","); } result.append(")"); return result.toString(); } }