package org.simantics.graph.query; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.TIntHashSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.simantics.databoard.adapter.AdaptException; import org.simantics.databoard.adapter.RuntimeAdaptException; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.type.Datatype; import org.simantics.graph.store.GraphStore; import org.simantics.graph.store.IdRes; import org.simantics.graph.store.IdentityStore; import org.simantics.graph.store.PathPattern; import org.simantics.graph.store.StatementStore; public class CompositeGraph implements IGraph { ArrayList fragments = new ArrayList(); Paths paths; public CompositeGraph(Paths paths) { this.paths = paths; } public void addFragment(GraphStore fragment) { fragments.add(fragment); } public void undoAddFragment() { fragments.remove(fragments.size()-1); } public void addFragments(Collection fragments) { fragments.addAll(fragments); } protected void rawGetObjects(GraphStore fragment, int subject, Res predicate, Collection result) { int predicateId; if(predicate instanceof Path) { predicateId = fragment.identities.pathToId((Path)predicate); if(predicateId < 0) return; } else { IdRes idPredicate = (IdRes)predicate; if(idPredicate.fragment != fragment) return; predicateId = idPredicate.id; } TIntArrayList objects = fragment.statements.getObjects(subject, predicateId); fragment.addIdsToResult(objects, result); } private void rawGetObjects(Res subject, Res predicate, Collection result) { if(subject instanceof Path) { Path path = (Path)subject; for(GraphStore fragment : fragments) { int id = fragment.identities.pathToId(path); if(id >= 0) rawGetObjects(fragment, id, predicate, result); } } else { IdRes idRes = (IdRes)subject; rawGetObjects(idRes.fragment, idRes.id, predicate, result); } } public boolean hasRawObjects(Res subject, Path predicate) { ArrayList result = new ArrayList(); rawGetObjects(subject, predicate, result); return !result.isEmpty(); } @Override public Collection rawGetObjects(Res subject, Res predicate) { ArrayList result = new ArrayList(); rawGetObjects(subject, predicate, result); return result; } @Override public Res singleRawObject(Res subject, Res predicate) throws NoUniqueObjectException { ArrayList result = new ArrayList(1); rawGetObjects(subject, predicate, result); if(result.size() != 1) throw new NoUniqueObjectException("No unique objects (" + result.size()+ ") for " + subject + " -> " + predicate); return result.get(0); } @Override public Collection getTypes(Res subject) { THashSet result = new THashSet(); rawGetObjects(subject, paths.InstanceOf, result); for(Res type : result.toArray(new Res[result.size()])) collectSupertypes(type, result); return result; } public Collection getSupertypes(Res subject) { THashSet result = new THashSet(); result.add(subject); collectSupertypes(subject, result); return result; } private void collectSupertypes(Res type, THashSet result) { for(Res supertype : rawGetObjects(type, paths.Inherits)) if(result.add(supertype)) collectSupertypes(supertype, result); } @Override public Collection getObjects(Res subject, Res predicate) { ArrayList result = new ArrayList(); rawGetObjects(subject, predicate, result); for(Res type : getTypes(subject)) for(Res assertion : rawGetObjects(type, paths.Asserts)) { Res pred = singleRawObject(assertion, paths.HasPredicate); if(equals(pred, predicate)) result.add(singleRawObject(assertion, paths.HasObject)); } return result; } public Collection getAssertedObjects(Res subject, Path predicate) { ArrayList result = new ArrayList(); for(Res type : getSupertypes(subject)) for(Res assertion : rawGetObjects(type, paths.Asserts)) { Res pred = singleRawObject(assertion, paths.HasPredicate); if(equals(pred, predicate)) result.add(singleRawObject(assertion, paths.HasObject)); } return result; } private static boolean equals(Res r1, Res r2) { return r1.equals(r2); } interface ResourceProcedure { public void execute(GraphStore fragment, int id); } interface ResourceFunction { public T execute(GraphStore fragment, int id); } public void forEachFragmentContaining(Res resource, ResourceProcedure proc) { if(resource instanceof Path) { Path path = (Path)resource; for(GraphStore fragment : fragments) { int id = fragment.identities.pathToId(path); if(id >= 0) proc.execute(fragment, id); } } else { IdRes res = (IdRes)resource; proc.execute(res.fragment, res.id); } } public T apply(Res resource, ResourceFunction func) { if(resource instanceof Path) { Path path = (Path)resource; for(GraphStore fragment : fragments) { int id = fragment.identities.pathToId(path); if(id >= 0) { T value = func.execute(fragment, id); if(value != null) return value; } } return null; } else { IdRes res = (IdRes)resource; return func.execute(res.fragment, res.id); } } private static ResourceFunction getDatatype = new ResourceFunction() { @Override public Datatype execute(GraphStore fragment, int id) { return fragment.values.getDatatypeValue(id); } }; private static ResourceFunction getValue = new ResourceFunction() { @Override public Variant execute(GraphStore fragment, int id) { return fragment.values.getByteValue(id); } }; THashMap datatypeCache = new THashMap(); @Override public Datatype getDatatype(Res resource) { for(Res dt : getObjects(resource, paths.HasDatatype)) { Datatype type = datatypeCache.get(dt); if(type == null) { type = apply(dt, getDatatype); datatypeCache.put(dt, type); } return type; } return null; } @Override public Datatype getAssertedDatatype(Res resource) { for(Res dt : getAssertedObjects(resource, paths.HasDatatype)) { Datatype type = datatypeCache.get(dt); if(type == null) { type = apply(dt, getDatatype); datatypeCache.put(dt, type); } return type; } return null; } @Override public Variant getValue(Res resource) { return apply(resource, getValue); } @Override public Object getValue(Res resource, Binding binding) throws NoValueException { Variant value = getValue(resource); if(value == null) throw new NoValueException(); try { return value.getValue(binding); } catch (AdaptException e) { throw new RuntimeAdaptException(e); } } @Override public void setValue(Res resource, Object value, Binding binding) { final Variant variant = new Variant(binding, value); apply(resource, new ResourceFunction() { @Override public Object execute(GraphStore fragment, int id) { fragment.values.setValue(id, variant); return null; } }); } /** * Tells in how many fragments the resource occurs. */ public int countOccurences(Res resource) { if(resource instanceof IdRes) return 1; else if(resource instanceof Path) { Path path = (Path)resource; int count = 0; for(GraphStore fragment : fragments) if(fragment.identities.contains(path)) ++count; return count; } else return 0; } private void collectSubtypes(THashSet types, Res type) { if(types.add(type)) for(Res subtype : rawGetObjects(type, paths.SupertypeOf)) collectSubtypes(types, subtype); } @Override public Collection getInstances(Res supertype) { THashSet types = new THashSet(); collectSubtypes(types, supertype); ArrayList result = new ArrayList(); fragmentLoop: for(GraphStore fragment : fragments) { IdentityStore identities = fragment.identities; StatementStore statements = fragment.statements; TIntHashSet ids = new TIntHashSet(types.size()); for(Res type : types) { if(type instanceof Path) { int id = identities.pathToId((Path)type); if(id >= 0) ids.add(id); } else { IdRes idRes = (IdRes)type; if(idRes.fragment == fragment) ids.add(idRes.id); } } if(ids.isEmpty()) continue; int instanceOfId = identities.pathToId(paths.InstanceOf); if(instanceOfId < 0) continue; int resourceCount = identities.getResourceCount(); nextResource: for(int i=0;i getChildren(Res res) { if(res instanceof Path) { THashSet result = new THashSet(); for(GraphStore store : fragments) { IdentityStore ids = store.identities; int id = ids.pathToId((Path)res); if(id >= 0) { for(int child : ids.getChildren(id)) result.add(store.idToRes(child)); } } return result; } else return Collections.emptyList(); } public Collection searchByPattern(String pattern) { THashSet result = new THashSet(); PathPattern pathPattern = PathPattern.compile(pattern); for(GraphStore store : fragments) pathPattern.search(store.identities, result); return result; } @Override public Paths getPaths() { return paths; } }