package org.simantics.db.common.utils; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.IsParent; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.PossibleObjectWithType; import org.simantics.db.common.request.PossibleOwner; import org.simantics.db.exception.DatabaseException; import org.simantics.db.service.ClusteringSupport; import org.simantics.layer0.Layer0; import org.simantics.utils.datastructures.collections.CollectionUtils; public class CommonDBUtils { public static boolean isParent(ReadGraph graph, Resource possibleParent, Resource possibleChild) throws DatabaseException { return graph.sync(new IsParent(possibleParent, possibleChild)); } public static Resource parent(ReadGraph graph, Resource child) throws DatabaseException { return graph.getSingleObject(child, Layer0.getInstance(graph).PartOf); } public static String possibleRelatedString(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException { return graph.getRelatedValue(subject, relation, Bindings.STRING); } public static Integer possibleRelatedInteger(ReadGraph graph, Resource subject, Resource relation) throws DatabaseException { return graph.getRelatedValue(subject, relation, Bindings.INTEGER); } public static Resource getPossibleOwner(ReadGraph graph, Resource resource) throws DatabaseException { return graph.syncRequest(new PossibleOwner(resource)); } public static Resource commonAncestor(ReadGraph graph, Resource r1, Resource r2) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); if(r1.equals(r2)) return r1; HashSet visited = new HashSet(); visited.add(r1); visited.add(r2); while(true) { if(r1 != null) { r1 = graph.getPossibleObject(r1, L0.IsOwnedBy); if(r1 != null) if(!visited.add(r1)) return r1; } else if(r2 == null) return null; if(r2 != null) { r2 = graph.getPossibleObject(r2, L0.IsOwnedBy); if(r2 != null) if(!visited.add(r2)) return r2; } } } public static Resource getNearestOwner(ReadGraph graph, Collection resources) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); Set direct = new HashSet(); Set owners = new HashSet(); for(Resource r : resources) { Collection objects = graph.getObjects(r, L0.IsOwnedBy); // FIXME: // TODO: getObjects returns duplicate entries (https://www.simantics.org/redmine/issues/4885) and therefore direct is Set. Fix getObjects to not return duplicate entries if (objects.size() > 1) objects = new HashSet(objects); if (objects.size() == 1) direct.addAll(objects); else if (objects.isEmpty()) { for(Statement stm : graph.getStatements(r, L0.IsWeaklyRelatedTo)) { Resource inverse = graph.getPossibleInverse(stm.getPredicate()); if(inverse != null) { if(graph.isSubrelationOf(inverse, L0.IsRelatedTo)) { // Filter away tags if(!r.equals(stm.getObject())) owners.add(stm.getObject()); } } } } else { System.err.println("Multiple owners for " + graph.getPossibleURI(r) + " id : " + r); for (Resource r2 : objects) System.err.println("owner : " + graph.getPossibleURI(r2) + " id " + r2); return null; } } if(!direct.isEmpty()) { Iterator iter = direct.iterator(); Resource common = iter.next(); while (iter.hasNext()) { Resource other = iter.next(); common = commonAncestor(graph, common, other); if (common == null) break; } if(common != null) owners.add(common); } if(!Collections.disjoint(owners, resources)) { System.err.println("Overlapping owners:"); for(Resource r : resources) System.err.println("-resource " + NameUtils.getSafeName(graph, r, true)); for(Resource r : owners) System.err.println("-owner " + NameUtils.getSafeName(graph, r, true)); return null; } if(owners.size() == 1) return owners.iterator().next(); if(owners.size() == 0) return null; return getNearestOwner(graph, owners); } public static Resource getClusterSetForNewResource(ReadGraph graph, Resource ... resources) throws DatabaseException { if(resources.length == 1) return getClusterSetForNewResource(graph, resources[0]); Resource owner = getNearestOwner(graph, CollectionUtils.toList(resources)); if(owner == null) return null; return getClusterSetForNewResource(graph, owner, new HashSet()); } public static Resource getClusterSetForNewResource(ReadGraph graph, Collection resources) throws DatabaseException { if(resources.size() == 1) return getClusterSetForNewResource(graph, resources.iterator().next()); Resource owner = getNearestOwner(graph, resources); return getClusterSetForNewResource(graph, owner, new HashSet()); } public static Resource getClusterSetForNewResource(ReadGraph graph, Resource resource, Set visited) throws DatabaseException { ClusteringSupport cs = graph.getService(ClusteringSupport.class); if(cs.isClusterSet(resource)) return resource; Resource owner = getPossibleOwner(graph, resource); if(owner == null || owner == resource) return null; if(!visited.add(owner)) return null; return getClusterSetForNewResource(graph, owner, visited); } public static Resource getClusterSetForNewResource(ReadGraph graph, Resource r) throws DatabaseException { return getClusterSetForNewResource(graph, r, new HashSet()); } public static void selectClusterSet(WriteGraph graph, Collection resources) throws DatabaseException { Resource clusterSet = getClusterSetForNewResource(graph, resources); if(clusterSet == null) clusterSet = graph.getRootLibrary(); graph.setClusterSet4NewResource(clusterSet); } public static void selectClusterSet(WriteGraph graph, Resource ... resources) throws DatabaseException { Resource clusterSet = getClusterSetForNewResource(graph, resources); if(clusterSet == null) clusterSet = graph.getRootLibrary(); graph.setClusterSet4NewResource(clusterSet); } public static void selectClusterSet(WriteGraph graph, Resource resource) throws DatabaseException { Resource clusterSet = getClusterSetForNewResource(graph, resource); if(clusterSet == null) clusterSet = graph.getRootLibrary(); graph.setClusterSet4NewResource(clusterSet); } public static List objectsWithType(ReadGraph graph, Resource subject, Resource relation, Resource type) throws DatabaseException { return new ArrayList(graph.syncRequest(new ObjectsWithType(subject, relation, type))); } public static Resource possibleObjectWithType(ReadGraph graph, Resource subject, Resource relation, Resource type) throws DatabaseException { return graph.syncRequest(new PossibleObjectWithType(subject, relation, type)); } }