1 package org.simantics.structural2.variables;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
12 import org.simantics.databoard.Bindings;
13 import org.simantics.db.ReadGraph;
14 import org.simantics.db.Resource;
15 import org.simantics.db.Statement;
16 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
17 import org.simantics.db.common.request.BinaryRead;
18 import org.simantics.db.common.request.ResourceRead;
19 import org.simantics.db.common.request.TransientUnaryRead;
20 import org.simantics.db.common.utils.CommonDBUtils;
21 import org.simantics.db.common.utils.NameUtils;
22 import org.simantics.db.exception.DatabaseException;
23 import org.simantics.db.exception.NoSingleResultException;
24 import org.simantics.db.layer0.exception.MissingVariableException;
25 import org.simantics.db.layer0.exception.MissingVariableValueException;
26 import org.simantics.db.layer0.request.VariableRead;
27 import org.simantics.db.layer0.variable.Variable;
28 import org.simantics.db.service.CollectionSupport;
29 import org.simantics.db.service.QueryControl;
30 import org.simantics.layer0.Layer0;
31 import org.simantics.modeling.ModelingResources;
32 import org.simantics.structural.stubs.StructuralResource2;
33 import org.simantics.structural2.Functions;
34 import org.simantics.structural2.Functions.InterfaceResolution;
35 import org.simantics.structural2.queries.ConnectionSet;
36 import org.simantics.structural2.utils.StructuralUtils;
37 import org.simantics.structural2.utils.StructuralUtils.StructuralComponentClass;
38 import org.simantics.structural2.variables.StandardProceduralChildVariable.FixedConnection;
39 import org.simantics.utils.datastructures.Pair;
41 import gnu.trove.map.hash.THashMap;
42 import gnu.trove.set.hash.THashSet;
44 public class ConnectionBrowser {
47 * Finds the components connected by the connection. Also connections
51 * @param connection A connection whose related modules are searched.
52 * @param configuration A variable that represents the composite where the connection belongs to.
53 * @return A map whose keys are components and they are mapped to
56 public static Collection<ResourceWithContext> findConnectedComponents(
57 ReadGraph graph, Resource connection, Variable configuration)
58 throws DatabaseException {
60 ArrayList<ResourceWithContext> result =
61 new ArrayList<ResourceWithContext>();
62 THashSet<Resource> visitedConnections = new THashSet<Resource>();
65 findConnectedComponents(graph, connection, configuration, result,
70 private static void findConnectedComponents(
71 ReadGraph graph, Resource connection, Variable configuration,
72 ArrayList<ResourceWithContext> result,
73 THashSet<Resource> visitedConnections) throws DatabaseException {
74 if(visitedConnections.add(connection)) {
75 StructuralResource2 STR = StructuralResource2.getInstance(graph);
76 Layer0 L0 = Layer0.getInstance(graph);
78 // Browse related components
79 for(Statement stat : graph.getStatements(connection, STR.Connects)) {
80 Resource component = stat.getObject();
81 Resource relation = graph.getInverse(stat.getPredicate());
82 //System.out.println(NameUtils.getSafeName(graph, component) + "." + NameUtils.getSafeName(graph, relation));
83 Resource boundConnection = graph.getPossibleObject(relation, STR.IsBoundBy);
84 Resource type = StructuralUtils.getComponentType(graph, configuration, component);
86 //Resource type = StructuralUtils.getComponentType(graph, configuration, component);
87 //Resource type = newContext != null ? newContext.getPossibleType(graph) : graph.getPossibleObject(component, L0.InstanceOf);
88 Resource def = type != null ? graph.getPossibleObject(type, STR.IsDefinedBy) : null;
89 if(boundConnection != null && def != null) {
90 // The connection point is bound in component type
91 Variable newContext = configuration.browsePossible(graph, component);
92 Resource newComposite = getCompositeOfConnection(graph, boundConnection);
93 if(newContext != null && newComposite != null) {
94 newContext = browse(graph, def, newContext, newComposite);
95 if (newContext != null)
96 findConnectedComponents(graph, boundConnection,
98 result, visitedConnections);
102 //System.out.println("added result");
103 // A primitive connection point
104 Variable context = configuration.browsePossible(graph, component);
106 result.add(new ResourceWithContext(component, context));
110 // Browse over connection joins
111 for(Resource join : graph.getObjects(connection, STR.IsJoinedBy))
112 for(Resource otherConnection : graph.getObjects(join, STR.Joins))
113 if(!connection.equals(otherConnection)) {
114 Resource sourceComposite = getCompositeOfConnection(graph, connection);
115 Resource targetComposite = getCompositeOfConnection(graph, otherConnection);
116 if (sourceComposite != null && targetComposite != null) {
117 Variable sibling = browseSibling(graph,
122 findConnectedComponents(graph, otherConnection,
123 sibling, result, visitedConnections);
129 for(Resource relation : graph.getObjects(connection, STR.Binds)) {
130 Resource composite = getCompositeOfConnection(graph, connection);
131 if (composite == null)
134 Variable curConfiguration = configuration;
135 while(!graph.hasStatement(composite, STR.Defines)) {
136 composite = graph.getSingleObject(composite, L0.PartOf);
137 curConfiguration = curConfiguration.getParent(graph);
139 Variable parent = curConfiguration.getParent(graph);
140 Resource component = curConfiguration.getRepresents(graph);
141 for(Resource c : graph.getObjects(component, relation))
142 findConnectedComponents(graph, c,
143 parent, result, visitedConnections);
145 } catch(NoSingleResultException e) {
146 } catch(MissingVariableException e) {
147 } catch(MissingVariableValueException e) {
152 public static Collection<VariableConnectionPointDescriptor> drill(ReadGraph graph, VariableConnectionPointDescriptor pair) throws DatabaseException {
154 Collection<InterfaceResolution> interfaceDescription = pair.getInterfaceDescription(graph);
155 if(interfaceDescription != null && interfaceDescription.size() > 0) {
157 Variable cp = pair.getVariable(graph);
158 Variable context = cp.getParent(graph);
159 String cpName = cp.getName(graph);
161 Collection<VariableConnectionPointDescriptor> result = new ArrayList<VariableConnectionPointDescriptor>();
162 for(InterfaceResolution r : interfaceDescription) {
163 if(r.interfaceName.equals(cpName)) {
164 String path = Functions.resolveInterfacePath(graph, context, r.componentName, r.connectionPoint);
165 result.add(new BrowseConnectionDescriptor(context, path));
169 if(result.isEmpty()) return null;
174 return Collections.singleton(pair);
179 public static class JoinConnections extends ResourceRead<Collection<Resource>> {
181 public JoinConnections(Resource join) {
186 public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {
187 ConnectionSet cs = new ConnectionSet(graph);
188 cs.addJoin(graph, resource);
189 return cs.getConnections();
195 public static final class VariableChildren extends TransientUnaryRead<Variable, Map<Resource,Variable>> {
197 public VariableChildren(ReadGraph graph, Variable variable) throws DatabaseException {
198 super(graph, variable);
201 public VariableChildren(ReadGraph graph, QueryControl qc, Variable variable) throws DatabaseException {
202 super(graph, qc, variable);
206 public Map<Resource, Variable> perform(ReadGraph graph, Variable parameter) throws DatabaseException {
207 CollectionSupport cs = graph.getService(CollectionSupport.class);
208 Map<Resource,Variable> result = cs.createMap(Variable.class);
209 for(Variable child : parameter.getChildren(graph)) {
210 Resource represents = child.getPossibleRepresents(graph);
211 if(represents != null) result.put(represents, child);
218 static Variable resolve(ReadGraph graph, Variable base, Resource component) throws DatabaseException {
219 Map<Resource,Variable> map = graph.syncRequest(new VariableChildren(graph, base), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());
220 Variable result = map.get(component);
221 if(result != null) return result;
223 Layer0 L0 = Layer0.getInstance(graph);
224 Resource parent = graph.getPossibleObject(component, L0.PartOf);
225 if(parent == null) return null;
226 Variable v = resolve(graph, base, parent);
227 if (v == null) return null;
228 map = graph.syncRequest(new VariableChildren(graph, v), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());
229 return map.get(component);
233 public static class ConnectionComponentsWithAncestor extends TransientUnaryRead<Resource, List<Resource>> {
235 final private List<Resource> result;
237 public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn) throws DatabaseException {
238 this(graph, conn, null);
241 public ConnectionComponentsWithAncestor(ReadGraph graph, QueryControl qc, Resource conn, List<Resource> result) throws DatabaseException {
242 super(graph, qc, conn);
243 this.result = result;
246 public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn, List<Resource> result) throws DatabaseException {
248 this.result = result;
251 private ConnectionSet connSet(ReadGraph graph, Resource r ) throws DatabaseException {
252 ConnectionSet cs = new ConnectionSet(graph);
253 cs.addConnection(graph, r);
258 public List<Resource> perform(ReadGraph graph, Resource resource) throws DatabaseException {
260 if(result != null) return result;
262 Layer0 L0 = Layer0.getInstance(graph);
263 StructuralResource2 STR = StructuralResource2.getInstance(graph);
264 CollectionSupport colls = graph.getService(CollectionSupport.class);
265 THashSet<Resource> ancestorGenerators = new THashSet<Resource>();
266 Set<Resource> parts = colls.createSet();
267 ConnectionSet cs = connSet(graph, resource);
268 for(Resource connRes : cs.getConnections()) {
269 for(Statement stm : graph.getStatements(connRes, STR.Connects)) {
270 Resource component = stm.getObject();
271 Resource parent = graph.getPossibleObject(component, L0.PartOf);
272 if(parent != null && !graph.isInstanceOf(component, ModelingResources.getInstance(graph).ReferenceElement))
273 ancestorGenerators.add(parent);
277 for (Resource join : cs.getJoins()) {
279 for (Resource composite : graph.getObjects(join, STR.JoinsComposite))
280 ancestorGenerators.add(composite);
282 Resource ancestor = ancestorGenerators.size() == 1 ? ancestorGenerators.iterator().next() : CommonDBUtils.getNearestOwner(graph, ancestorGenerators);
284 List<Resource> result = colls.createList();
285 result.add(ancestor);
286 result.addAll(colls.asSortedList(parts));
288 if(parameter != WITH_PARENT) {
289 for(int i=1;i<result.size();i++) {
290 Resource r = result.get(i);
292 if(!r.equals(resource))
293 graph.syncRequest(new ConnectionComponentsWithAncestor(graph, r, result), TransientCacheAsyncListener.<List<Resource>>instance());
303 public static Collection<VariableConnectionPointDescriptor> climb(ReadGraph graph, Variable child, Resource cp, String subPath_) throws DatabaseException {
305 boolean isStructural = false;
307 Variable curConfiguration = child.getParent(graph);
311 Collection<InterfaceResolution> interfaceDescription = Functions.computeInterfacePaths(graph, curConfiguration);
312 if(interfaceDescription != null) {
313 isStructural = interfaceDescription != Functions.BUILTIN_STRUCTURAL_CPS;
314 if(interfaceDescription.size() > 0) {
316 if(subPath_ == null) {
318 String childName = child.getName(graph);
319 for(InterfaceResolution r : interfaceDescription) {
320 if(r.componentName.equals(childName) && r.connectionPoint.equals(cp)) {
321 Variable pConn = curConfiguration.getPossibleProperty(graph, r.interfaceName);
323 Resource cp2 = pConn.getPossiblePredicateResource(graph);
324 Collection<VariableConnectionPointDescriptor> res = climb(graph, curConfiguration, cp2, null);
325 if(res != null) return res;
327 return Collections.emptyList();
332 throw new UnsupportedOperationException("");
339 if(child instanceof StandardProceduralChildVariable) {
341 Variable conn = child.getPossibleProperty(graph, cp);
342 FixedConnection fc = (FixedConnection)conn.getValue(graph);
343 Set<VariableConnectionPointDescriptor> result = new THashSet<VariableConnectionPointDescriptor>(1+fc.cps.size());
344 result.add(new ComponentConnectionDescriptor(child, cp));// (graph, STR, curConfiguration, "/" + c.name + "#" + conn.getName(graph)));
345 for(Pair<String,Resource> cpzz : fc.cps) {
346 if(cpzz.first == null) {
347 throw new DatabaseException("Lifted connection was not resolved.");
349 result.add(new PairConnectionDescriptor(curConfiguration, cpzz));
356 Resource represents = child.getRepresents(graph);
360 Collection<Resource> conns = graph.getObjects(represents, res);
361 HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();
362 for(Resource c : conns) {
363 List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance());
364 for(Resource r : rs) {
365 System.err.println("--connections " + NameUtils.getSafeName(graph, r));
367 result.addAll(graph.syncRequest(ConnectionVariables.forStructural(graph, curConfiguration, rs)));
368 for(VariableConnectionPointDescriptor desc2 : result) {
369 reportDescriptor(graph, desc2);
376 Resource connection = graph.getPossibleObject(represents, res);
377 if(connection != null) {
378 List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, connection), TransientCacheAsyncListener.<List<Resource>>instance());
379 for(Resource r : rs) {
380 System.err.println("--connections " + NameUtils.getSafeName(graph, r));
382 return graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs));
385 Collection<Resource> conns = graph.getObjects(represents, res);
386 HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();
387 for(Resource c : conns) {
388 List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance());
389 result.addAll(graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs)));
400 public static void reportDescriptor(ReadGraph graph, VariableConnectionPointDescriptor d) throws DatabaseException {
402 if(d instanceof ActualConnectionDescriptor) {
403 ActualConnectionDescriptor d2 = (ActualConnectionDescriptor)d;
405 System.err.println("--ActualConnectionPointDescriptor2");
406 System.err.println("---root: " + d2.root.getURI(graph));
407 System.err.println("---component: " + graph.getPossibleURI(d2.component));
408 System.err.println("---type: " + graph.getPossibleURI(d2.componentType));
409 System.err.println("---cp: " + graph.getPossibleURI(d2.cp));
410 System.err.println("---var: " + d2.getVariable(graph).getURI(graph));
415 public static class ConnectionVariables extends BinaryRead<Variable, List<Resource>, Collection<VariableConnectionPointDescriptor>> {
417 private ConnectionVariables(Variable parameter1, List<Resource> parameter2) {
418 super(parameter1, parameter2);
421 public static ConnectionVariables forConfiguration(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {
422 return new ConnectionVariables(parent(graph, configuration, rs.get(0)), rs);
425 public static ConnectionVariables forStructural(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {
426 return new ConnectionVariables(configuration, rs);
430 * Finds the parent variable of <code>configuration</code> that
431 * represents <code>ancestor</code>.
434 * @param configuration
437 * @throws DatabaseException if no parent was found that represents ancestor
439 private static Variable parent(ReadGraph graph, Variable configuration, Resource ancestor) throws DatabaseException {
440 Variable v = configuration;
441 Resource represents = v.getRepresents(graph);
442 while(!represents.equals(ancestor)) {
443 v = v.getParent(graph);
445 throw new DatabaseException(
446 "parent representing ancestor not found for variable, configuration="
447 + safeURI(graph, configuration)
449 + NameUtils.getURIOrSafeNameInternal(graph, ancestor));
451 represents = v.getRepresents(graph);
457 public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph) throws DatabaseException {
458 if(parameter == null) return Collections.emptyList();
459 System.err.println("ConnectionVariables " + parameter.getURI(graph));
460 StructuralResource2 STR = StructuralResource2.getInstance(graph);
461 ArrayList<VariableConnectionPointDescriptor> result = null;
462 for(int i=1;i<parameter2.size();i++) {
463 Resource connRes = parameter2.get(i);
464 for(Statement stm : graph.getStatements(connRes, STR.Connects)) {
465 Layer0 L0 = Layer0.getInstance(graph);
466 Resource component = stm.getObject();
467 Resource connectionPoint = graph.getInverse(stm.getPredicate());
468 if(result == null) result = new ArrayList<VariableConnectionPointDescriptor>();
469 String componentName = graph.getRelatedValue(component, L0.HasName, Bindings.STRING);
470 if(parameter.getURI(graph).endsWith("SelectionView/Instance") && componentName.equals("Explorer1"))
471 System.err.println("asd");
472 Variable possibleChild = parameter.getPossibleChild(graph, componentName);
473 if(possibleChild != null) {
474 result.add(new ActualConnectionDescriptor(parameter, component, possibleChild.getType(graph), connectionPoint));
476 throw new DatabaseException("No child with name " + componentName + " could be resolved for variable " + parameter.getURI(graph));
480 if(result == null) return Collections.emptyList();
486 static class IsLeafType extends ResourceRead<Boolean> {
488 protected IsLeafType(Resource type) {
493 public Boolean perform(ReadGraph graph) throws DatabaseException {
495 StructuralComponentClass clazz = StructuralComponentClass.get(graph, resource);
496 return StructuralComponentClass.PRIMITIVE.equals(clazz);
502 static class ChildMapOfVariable extends VariableRead<Map<Resource,Variable>> {
504 public ChildMapOfVariable(Variable variable) {
509 public Map<Resource, Variable> perform(ReadGraph graph) throws DatabaseException {
510 HashMap<Resource,Variable> result = new HashMap<Resource,Variable>();
511 for(Variable child : variable.getChildren(graph)) {
512 Resource represents = child.getPossibleRepresents(graph);
513 if(represents != null) result.put(represents, child);
521 * Given a root composite, related variable and some other component inside the composite,
522 * finds the related variable for that component.
524 public static Variable browse(ReadGraph graph, Resource root, Variable rootContext, Resource target) throws DatabaseException {
525 if(target.equals(root))
528 Layer0 L0 = Layer0.getInstance(graph);
529 String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);
530 Resource parent = graph.getPossibleObject(target, L0.PartOf);
531 if(name == null || parent == null)
533 Variable parentVariable = browse(graph, root, rootContext, parent);
534 if(parentVariable == null)
536 return parentVariable.getPossibleChild(graph, name);
541 * Finds a variable whose location related to sourceContext is the same as
542 * between target and source. In other words, the method solves {@code targetContext}
543 * in the following equations:
545 * URI(source) = resourceURIBase + sourceSuffix
546 * URI(sourceContext) = variableURIBase + sourceSuffix
547 * URI(target) = resourceURIBase + targetSuffix
548 * URI(targetContext) = variableURIBase + targetSuffix
551 public static Variable browseSibling(ReadGraph graph, Resource source, Variable sourceContext, Resource target) throws DatabaseException {
552 Layer0 L0 = Layer0.getInstance(graph);
553 THashMap<Resource, Variable> sourceMap = new THashMap<Resource, Variable>();
554 while(source != null && sourceContext != null) {
555 sourceMap.put(source, sourceContext);
556 source = graph.getPossibleObject(source, L0.PartOf);
557 sourceContext = sourceContext.getParent(graph);
559 return browseSibling(graph, sourceMap, target);
562 private static Variable browseSibling(ReadGraph graph, THashMap<Resource, Variable> sourceMap, Resource target) throws DatabaseException {
563 Layer0 L0 = Layer0.getInstance(graph);
564 Variable result = sourceMap.get(target);
567 String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);
568 Resource parent = graph.getPossibleObject(target, L0.PartOf);
569 if(name == null || parent == null)
571 Variable parentVariable = browseSibling(graph, sourceMap, parent);
572 if(parentVariable == null)
574 return parentVariable.getPossibleChild(graph, name);
578 * Returns the composite where the connection given as a parameter resides.
580 public static Resource getCompositeOfConnection(ReadGraph graph, Resource connection) throws DatabaseException {
581 Layer0 L0 = Layer0.getInstance(graph);
582 StructuralResource2 STR = StructuralResource2.getInstance(graph);
583 // First from connected components
584 for(Resource component : graph.getObjects(connection, STR.Connects))
585 for(Resource composite : graph.getObjects(component, L0.PartOf))
587 // It could be that the connection is only supported by joins (input flag -> output flag) - use diagram info TODO!!
588 Resource connToDiagramConn = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/ConnectionToDiagramConnection");
589 if(connToDiagramConn != null) {
590 Resource diagramConnection = graph.getPossibleObject(connection, connToDiagramConn);
591 if(diagramConnection != null) {
592 Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);
593 if(diagram != null) {
594 Resource diagramToComposite = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/DiagramToComposite");
595 if(diagramToComposite != null) {
596 return graph.getPossibleObject(diagram, diagramToComposite);
604 static class Flatten extends BinaryRead<Variable,Resource,Collection<VariableConnectionPointDescriptor>> {
606 public Flatten(Variable parameter1,
607 Resource parameter2) {
608 super(parameter1, parameter2);
612 public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph)
613 throws DatabaseException {
614 return doFlatten(graph, parameter, parameter2, null);
619 public static Collection<VariableConnectionPointDescriptor> flatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {
621 if(relationType == null) return graph.syncRequest(new Flatten(child, cp));
623 return doFlatten(graph, child, cp, relationType);
627 public static Collection<VariableConnectionPointDescriptor> doFlatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {
629 Set<VariableConnectionPointDescriptor> result = null;
630 Set<VariableConnectionPointDescriptor> needDrill = null;
632 String debug = child.getURI(graph) + " " + NameUtils.getSafeLabel(graph, cp);
633 System.err.println("doFlatten " + debug);
635 if(debug.endsWith("01/TreeTable01 parent"))
636 System.err.println("asd");
638 Collection<VariableConnectionPointDescriptor> climbed = climb(graph, child, cp, null);
639 for(VariableConnectionPointDescriptor desc : climbed) {
640 if(!desc.isLeaf(graph)) {
641 if(needDrill == null)
642 needDrill = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
646 result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
651 if(needDrill == null) {
653 * All descriptors were already flat - just take case of filtering
655 if(relationType != null) {
656 ArrayList<VariableConnectionPointDescriptor> filtered = new ArrayList<VariableConnectionPointDescriptor>(climbed.size());
657 for(VariableConnectionPointDescriptor desc : climbed)
658 if(filterByRelationType(graph, desc, relationType))
668 * There were some descriptors that require drill
670 for(VariableConnectionPointDescriptor top : needDrill) {
672 if(debug.endsWith("01/TreeTable01 parent"))
673 System.err.println("asd");
675 Collection<VariableConnectionPointDescriptor> drilled = drill(graph, top);
676 if(drilled != null) {
677 for(VariableConnectionPointDescriptor drill : drilled) {
678 if(relationType != null) {
679 if(!filterByRelationType(graph, drill, relationType))
683 result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
689 System.err.println("doFlatten finished: " + debug);
691 if(debug.endsWith("01/TreeTable01 parent"))
692 System.err.println("asd");
694 for(VariableConnectionPointDescriptor desc2 : result) {
695 reportDescriptor(graph, desc2);
702 private static boolean filterByRelationType(ReadGraph graph, VariableConnectionPointDescriptor desc, Resource relationType) throws DatabaseException {
703 Resource predicateResource = desc.getConnectionPointResource(graph);
704 return predicateResource != null && graph.isInstanceOf(predicateResource, relationType);
707 private static String safeURI(ReadGraph graph, Variable v) {
709 return "null variable";
711 return v.getURI(graph);
712 } catch (DatabaseException e) {