--- /dev/null
+package org.simantics.structural2.variables;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
+import org.simantics.db.common.request.BinaryRead;\r
+import org.simantics.db.common.request.ResourceRead;\r
+import org.simantics.db.common.request.TransientUnaryRead;\r
+import org.simantics.db.common.utils.CommonDBUtils;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.NoSingleResultException;\r
+import org.simantics.db.layer0.exception.MissingVariableException;\r
+import org.simantics.db.layer0.exception.MissingVariableValueException;\r
+import org.simantics.db.layer0.request.VariableRead;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.service.CollectionSupport;\r
+import org.simantics.db.service.QueryControl;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.Functions;\r
+import org.simantics.structural2.Functions.InterfaceResolution;\r
+import org.simantics.structural2.queries.ConnectionSet;\r
+import org.simantics.structural2.variables.StandardProceduralChildVariable.FixedConnection;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+public class ConnectionBrowser {\r
+\r
+ /**\r
+ * Finds the components connected by the connection. Also connections\r
+ * in \r
+ * \r
+ * @param graph \r
+ * @param connection A connection whose related modules are searched.\r
+ * @param configuration A variable that represents the composite where the connection belongs to.\r
+ * @return A map whose keys are components and they are mapped to \r
+ * related variables.\r
+ */\r
+ public static Collection<ResourceWithContext> findConnectedComponents(\r
+ ReadGraph graph, Resource connection, Variable configuration) \r
+ throws DatabaseException {\r
+ // Create state\r
+ ArrayList<ResourceWithContext> result = \r
+ new ArrayList<ResourceWithContext>();\r
+ THashSet<Resource> visitedConnections = new THashSet<Resource>();\r
+\r
+ // Do actual work\r
+ findConnectedComponents(graph, connection, configuration, result,\r
+ visitedConnections);\r
+ return result;\r
+ }\r
+\r
+ private static void findConnectedComponents(\r
+ ReadGraph graph, Resource connection, Variable configuration,\r
+ ArrayList<ResourceWithContext> result,\r
+ THashSet<Resource> visitedConnections) throws DatabaseException {\r
+ if(visitedConnections.add(connection)) {\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+\r
+ // Browse related components\r
+ for(Statement stat : graph.getStatements(connection, STR.Connects)) {\r
+ Resource component = stat.getObject();\r
+ Resource relation = graph.getInverse(stat.getPredicate());\r
+ //System.out.println(NameUtils.getSafeName(graph, component) + "." + NameUtils.getSafeName(graph, relation));\r
+ Resource boundConnection = graph.getPossibleObject(relation, STR.IsBoundBy);\r
+ Resource type = graph.getPossibleObject(component, L0.InstanceOf);\r
+ Resource def = type != null ? graph.getPossibleObject(type, STR.IsDefinedBy) : null;\r
+ if(boundConnection != null && def != null) {\r
+ // The connection point is bound in component type\r
+ Variable newContext = configuration.browsePossible(graph, component);\r
+ Resource newComposite = getCompositeOfConnection(graph, boundConnection);\r
+ if(newContext != null && newComposite != null) {\r
+ newContext = browse(graph, def, newContext, newComposite);\r
+ if (newContext != null)\r
+ findConnectedComponents(graph, boundConnection,\r
+ newContext,\r
+ result, visitedConnections);\r
+ }\r
+ }\r
+ else {\r
+ //System.out.println("added result");\r
+ // A primitive connection point\r
+ Variable context = configuration.browsePossible(graph, component);\r
+ if (context != null)\r
+ result.add(new ResourceWithContext(component, context)); \r
+ }\r
+ }\r
+\r
+ // Browse over connection joins\r
+ for(Resource join : graph.getObjects(connection, STR.IsJoinedBy))\r
+ for(Resource otherConnection : graph.getObjects(join, STR.Joins))\r
+ if(!connection.equals(otherConnection)) {\r
+ Resource sourceComposite = getCompositeOfConnection(graph, connection);\r
+ Resource targetComposite = getCompositeOfConnection(graph, otherConnection);\r
+ if (sourceComposite != null && targetComposite != null) {\r
+ Variable sibling = browseSibling(graph, \r
+ sourceComposite,\r
+ configuration,\r
+ targetComposite);\r
+ if (sibling != null)\r
+ findConnectedComponents(graph, otherConnection,\r
+ sibling, result, visitedConnections);\r
+ }\r
+ }\r
+\r
+ // Browse to parents\r
+ try {\r
+ for(Resource relation : graph.getObjects(connection, STR.Binds)) {\r
+ Resource composite = getCompositeOfConnection(graph, connection);\r
+ if (composite == null)\r
+ continue;\r
+\r
+ Variable curConfiguration = configuration;\r
+ while(!graph.hasStatement(composite, STR.Defines)) {\r
+ composite = graph.getSingleObject(composite, L0.PartOf);\r
+ curConfiguration = curConfiguration.getParent(graph);\r
+ }\r
+ Variable parent = curConfiguration.getParent(graph);\r
+ Resource component = curConfiguration.getRepresents(graph);\r
+ for(Resource c : graph.getObjects(component, relation))\r
+ findConnectedComponents(graph, c, \r
+ parent, result, visitedConnections);\r
+ }\r
+ } catch(NoSingleResultException e) {\r
+ } catch(MissingVariableException e) {\r
+ } catch(MissingVariableValueException e) {\r
+ }\r
+ }\r
+ }\r
+\r
+ public static Collection<VariableConnectionPointDescriptor> drill(ReadGraph graph, VariableConnectionPointDescriptor pair) throws DatabaseException {\r
+\r
+ Collection<InterfaceResolution> interfaceDescription = pair.getInterfaceDescription(graph);\r
+ if(interfaceDescription != null && interfaceDescription.size() > 0) {\r
+\r
+ Variable cp = pair.getVariable(graph);\r
+ Variable context = cp.getParent(graph);\r
+ String cpName = cp.getName(graph);\r
+\r
+ Collection<VariableConnectionPointDescriptor> result = new ArrayList<VariableConnectionPointDescriptor>();\r
+ for(InterfaceResolution r : interfaceDescription) {\r
+ if(r.interfaceName.equals(cpName)) {\r
+ String path = Functions.resolveInterfacePath(graph, context, r.componentName, r.connectionPoint);\r
+ result.add(new BrowseConnectionDescriptor(context, path));\r
+ }\r
+ }\r
+ \r
+ if(result.isEmpty()) return null;\r
+ \r
+ return result;\r
+ \r
+ } else {\r
+ return Collections.singleton(pair);\r
+ }\r
+\r
+ }\r
+ \r
+ public static class JoinConnections extends ResourceRead<Collection<Resource>> {\r
+\r
+ public JoinConnections(Resource join) {\r
+ super(join);\r
+ }\r
+\r
+ @Override\r
+ public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {\r
+ ConnectionSet cs = new ConnectionSet(graph);\r
+ cs.addJoin(graph, resource);\r
+ return cs.getConnections();\r
+ }\r
+ \r
+ }\r
+\r
+ \r
+ public static final class VariableChildren extends TransientUnaryRead<Variable, Map<Resource,Variable>> {\r
+\r
+ public VariableChildren(ReadGraph graph, Variable variable) throws DatabaseException {\r
+ super(graph, variable);\r
+ }\r
+\r
+ public VariableChildren(ReadGraph graph, QueryControl qc, Variable variable) throws DatabaseException {\r
+ super(graph, qc, variable);\r
+ }\r
+\r
+ @Override\r
+ public Map<Resource, Variable> perform(ReadGraph graph, Variable parameter) throws DatabaseException {\r
+ CollectionSupport cs = graph.getService(CollectionSupport.class);\r
+ Map<Resource,Variable> result = cs.createMap(Variable.class);\r
+ for(Variable child : parameter.getChildren(graph)) {\r
+ Resource represents = child.getPossibleRepresents(graph);\r
+ if(represents != null) result.put(represents, child);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ }\r
+ \r
+ static Variable resolve(ReadGraph graph, Variable base, Resource component) throws DatabaseException {\r
+ Map<Resource,Variable> map = graph.syncRequest(new VariableChildren(graph, base), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());\r
+ Variable result = map.get(component);\r
+ if(result != null) return result;\r
+ else {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Resource parent = graph.getPossibleObject(component, L0.PartOf);\r
+ if(parent == null) return null;\r
+ Variable v = resolve(graph, base, parent);\r
+ if (v == null) return null;\r
+ map = graph.syncRequest(new VariableChildren(graph, v), TransientCacheAsyncListener.<Map<Resource,Variable>>instance());\r
+ return map.get(component);\r
+ }\r
+ }\r
+ \r
+ public static class ConnectionComponentsWithAncestor extends TransientUnaryRead<Resource, List<Resource>> {\r
+\r
+ final private List<Resource> result;\r
+\r
+ public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn) throws DatabaseException {\r
+ this(graph, conn, null);\r
+ }\r
+\r
+ public ConnectionComponentsWithAncestor(ReadGraph graph, QueryControl qc, Resource conn, List<Resource> result) throws DatabaseException {\r
+ super(graph, qc, conn);\r
+ this.result = result;\r
+ }\r
+\r
+ public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn, List<Resource> result) throws DatabaseException {\r
+ super(graph, conn);\r
+ this.result = result;\r
+ }\r
+\r
+ private ConnectionSet connSet(ReadGraph graph, Resource r ) throws DatabaseException {\r
+ ConnectionSet cs = new ConnectionSet(graph);\r
+ cs.addConnection(graph, r);\r
+ return cs;\r
+ }\r
+ \r
+ @Override\r
+ public List<Resource> perform(ReadGraph graph, Resource resource) throws DatabaseException {\r
+ \r
+ if(result != null) return result;\r
+ \r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+ CollectionSupport colls = graph.getService(CollectionSupport.class);\r
+ THashSet<Resource> ancestorGenerators = new THashSet<Resource>();\r
+ Set<Resource> parts = colls.createSet();\r
+ ConnectionSet cs = connSet(graph, resource);\r
+ for(Resource connRes : cs.getConnections()) {\r
+ for(Statement stm : graph.getStatements(connRes, STR.Connects)) {\r
+ Resource component = stm.getObject();\r
+ Resource parent = graph.getPossibleObject(component, L0.PartOf);\r
+ if(parent != null && !graph.isInstanceOf(component, ModelingResources.getInstance(graph).ReferenceElement))\r
+ ancestorGenerators.add(parent);\r
+ }\r
+ parts.add(connRes);\r
+ }\r
+ for (Resource join : cs.getJoins()) {\r
+ parts.add(join);\r
+ for (Resource composite : graph.getObjects(join, STR.JoinsComposite))\r
+ ancestorGenerators.add(composite);\r
+ }\r
+ Resource ancestor = ancestorGenerators.size() == 1 ? ancestorGenerators.iterator().next() : CommonDBUtils.getNearestOwner(graph, ancestorGenerators);\r
+ \r
+ List<Resource> result = colls.createList();\r
+ result.add(ancestor);\r
+ result.addAll(colls.asSortedList(parts));\r
+ \r
+ if(parameter != WITH_PARENT) {\r
+ for(int i=1;i<result.size();i++) {\r
+ Resource r = result.get(i);\r
+ // Cache 'em all\r
+ if(!r.equals(resource))\r
+ graph.syncRequest(new ConnectionComponentsWithAncestor(graph, r, result), TransientCacheAsyncListener.<List<Resource>>instance());\r
+ }\r
+ }\r
+ \r
+ return result;\r
+ \r
+ }\r
+ \r
+ }\r
+ \r
+ public static Collection<VariableConnectionPointDescriptor> climb(ReadGraph graph, Variable child, Resource cp, String subPath_) throws DatabaseException {\r
+ \r
+ boolean isStructural = false;\r
+\r
+ Variable curConfiguration = child.getParent(graph);\r
+\r
+ {\r
+\r
+ Collection<InterfaceResolution> interfaceDescription = Functions.computeInterfacePaths(graph, curConfiguration);\r
+ if(interfaceDescription != null) {\r
+ isStructural = interfaceDescription != Functions.BUILTIN_STRUCTURAL_CPS;\r
+ if(interfaceDescription.size() > 0) {\r
+ \r
+ if(subPath_ == null) {\r
+ \r
+ String childName = child.getName(graph);\r
+ for(InterfaceResolution r : interfaceDescription) {\r
+ if(r.componentName.equals(childName) && r.connectionPoint.equals(cp)) {\r
+ Variable pConn = curConfiguration.getPossibleProperty(graph, r.interfaceName);\r
+ if(pConn != null) {\r
+ Resource cp2 = pConn.getPossiblePredicateResource(graph);\r
+ Collection<VariableConnectionPointDescriptor> res = climb(graph, curConfiguration, cp2, null);\r
+ if(res != null) return res;\r
+ }\r
+ return Collections.emptyList();\r
+ }\r
+ }\r
+\r
+ } else {\r
+ throw new UnsupportedOperationException("");\r
+ }\r
+ }\r
+ }\r
+\r
+ }\r
+ \r
+ if(child instanceof StandardProceduralChildVariable) {\r
+ \r
+ Variable conn = child.getPossibleProperty(graph, cp);\r
+ FixedConnection fc = (FixedConnection)conn.getValue(graph);\r
+ Set<VariableConnectionPointDescriptor> result = new THashSet<VariableConnectionPointDescriptor>(1+fc.cps.size());\r
+ result.add(new ComponentConnectionDescriptor(child, cp));// (graph, STR, curConfiguration, "/" + c.name + "#" + conn.getName(graph)));\r
+ for(Pair<String,Resource> cpzz : fc.cps) {\r
+ if(cpzz.first == null) {\r
+ throw new DatabaseException("Lifted connection was not resolved.");\r
+ }\r
+ result.add(new PairConnectionDescriptor(curConfiguration, cpzz));\r
+ }\r
+ return result;\r
+ \r
+ } else {\r
+\r
+ Resource res = cp;\r
+ Resource represents = child.getRepresents(graph);\r
+\r
+ if(isStructural) {\r
+\r
+ Collection<Resource> conns = graph.getObjects(represents, res);\r
+ HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();\r
+ for(Resource c : conns) {\r
+ List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance()); \r
+ result.addAll(graph.syncRequest(ConnectionVariables.forStructural(graph, curConfiguration, rs)));\r
+ }\r
+ return result;\r
+ \r
+ } else {\r
+\r
+ Resource connection = graph.getPossibleObject(represents, res);\r
+ if(connection != null) {\r
+ List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, connection), TransientCacheAsyncListener.<List<Resource>>instance());\r
+ return graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs));\r
+ }\r
+ else {\r
+ Collection<Resource> conns = graph.getObjects(represents, res);\r
+ HashSet<VariableConnectionPointDescriptor> result = new HashSet<VariableConnectionPointDescriptor>();\r
+ for(Resource c : conns) {\r
+ List<Resource> rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.<List<Resource>>instance()); \r
+ result.addAll(graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs)));\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ }\r
+ \r
+ }\r
+ \r
+ }\r
+ \r
+ public static class ConnectionVariables extends BinaryRead<Variable, List<Resource>, Collection<VariableConnectionPointDescriptor>> {\r
+\r
+ private ConnectionVariables(Variable parameter1, List<Resource> parameter2) {\r
+ super(parameter1, parameter2);\r
+ }\r
+\r
+ public static ConnectionVariables forConfiguration(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {\r
+ return new ConnectionVariables(parent(graph, configuration, rs.get(0)), rs);\r
+ }\r
+\r
+ public static ConnectionVariables forStructural(ReadGraph graph, Variable configuration, List<Resource> rs) throws DatabaseException {\r
+ return new ConnectionVariables(configuration, rs);\r
+ }\r
+\r
+ /**\r
+ * Finds the parent variable of <code>configuration</code> that\r
+ * represents <code>ancestor</code>.\r
+ * \r
+ * @param graph\r
+ * @param configuration\r
+ * @param ancestor\r
+ * @return\r
+ * @throws DatabaseException if no parent was found that represents ancestor\r
+ */\r
+ private static Variable parent(ReadGraph graph, Variable configuration, Resource ancestor) throws DatabaseException {\r
+ Variable v = configuration;\r
+ Resource represents = v.getRepresents(graph);\r
+ while(!represents.equals(ancestor)) {\r
+ v = v.getParent(graph);\r
+ if (v == null) {\r
+ throw new DatabaseException(\r
+ "parent representing ancestor not found for variable, configuration="\r
+ + safeURI(graph, configuration)\r
+ + ", ancestor="\r
+ + NameUtils.getURIOrSafeNameInternal(graph, ancestor));\r
+ }\r
+ represents = v.getRepresents(graph);\r
+ }\r
+ return v;\r
+ }\r
+\r
+ @Override\r
+ public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph) throws DatabaseException {\r
+ if(parameter == null) return Collections.emptyList();\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+ ArrayList<VariableConnectionPointDescriptor> result = null;\r
+ for(int i=1;i<parameter2.size();i++) {\r
+ Resource connRes = parameter2.get(i);\r
+ for(Statement stm : graph.getStatements(connRes, STR.Connects)) {\r
+ Resource component = stm.getObject();\r
+ Resource connectionPoint = graph.getInverse(stm.getPredicate());\r
+ if(result == null) result = new ArrayList<VariableConnectionPointDescriptor>();\r
+ result.add(new ActualConnectionDescriptor(parameter, component, connectionPoint));\r
+ }\r
+ }\r
+ if(result == null) return Collections.emptyList();\r
+ return result;\r
+ }\r
+ \r
+ }\r
+ \r
+ static class IsLeafType extends ResourceRead<Boolean> {\r
+\r
+ protected IsLeafType(Resource type) {\r
+ super(type);\r
+ }\r
+\r
+ @Override\r
+ public Boolean perform(ReadGraph graph) throws DatabaseException {\r
+ \r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ if(graph.isInstanceOf(resource, STR.ProceduralComponentType)) return false;\r
+ if(graph.hasStatement(resource, STR.IsDefinedBy)) return false;\r
+ \r
+ return true;\r
+\r
+ }\r
+ \r
+ }\r
+ \r
+ static class ChildMapOfVariable extends VariableRead<Map<Resource,Variable>> {\r
+\r
+ public ChildMapOfVariable(Variable variable) {\r
+ super(variable);\r
+ }\r
+\r
+ @Override\r
+ public Map<Resource, Variable> perform(ReadGraph graph) throws DatabaseException {\r
+ HashMap<Resource,Variable> result = new HashMap<Resource,Variable>();\r
+ for(Variable child : variable.getChildren(graph)) {\r
+ Resource represents = child.getPossibleRepresents(graph);\r
+ if(represents != null) result.put(represents, child);\r
+ }\r
+ return result;\r
+ }\r
+ \r
+ }\r
+\r
+ /**\r
+ * Given a root composite, related variable and some other component inside the composite,\r
+ * finds the related variable for that component.\r
+ */\r
+ public static Variable browse(ReadGraph graph, Resource root, Variable rootContext, Resource target) throws DatabaseException {\r
+ if(target.equals(root))\r
+ return rootContext;\r
+ else {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);\r
+ Resource parent = graph.getPossibleObject(target, L0.PartOf);\r
+ if(name == null || parent == null)\r
+ return null;\r
+ Variable parentVariable = browse(graph, root, rootContext, parent);\r
+ if(parentVariable == null)\r
+ return null;\r
+ return parentVariable.getPossibleChild(graph, name);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Finds a variable whose location related to sourceContext is the same as \r
+ * between target and source. In other words, the method solves {@code targetContext}\r
+ * in the following equations:\r
+ * <pre>\r
+ * URI(source) = resourceURIBase + sourceSuffix\r
+ * URI(sourceContext) = variableURIBase + sourceSuffix\r
+ * URI(target) = resourceURIBase + targetSuffix\r
+ * URI(targetContext) = variableURIBase + targetSuffix\r
+ * </pre>\r
+ */\r
+ public static Variable browseSibling(ReadGraph graph, Resource source, Variable sourceContext, Resource target) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ THashMap<Resource, Variable> sourceMap = new THashMap<Resource, Variable>();\r
+ while(source != null && sourceContext != null) {\r
+ sourceMap.put(source, sourceContext);\r
+ source = graph.getPossibleObject(source, L0.PartOf);\r
+ sourceContext = sourceContext.getParent(graph);\r
+ }\r
+ return browseSibling(graph, sourceMap, target);\r
+ }\r
+\r
+ private static Variable browseSibling(ReadGraph graph, THashMap<Resource, Variable> sourceMap, Resource target) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Variable result = sourceMap.get(target);\r
+ if(result != null)\r
+ return result;\r
+ String name = (String)graph.getPossibleRelatedValue(target, L0.HasName, Bindings.STRING);\r
+ Resource parent = graph.getPossibleObject(target, L0.PartOf);\r
+ if(name == null || parent == null)\r
+ return null;\r
+ Variable parentVariable = browseSibling(graph, sourceMap, parent);\r
+ if(parentVariable == null)\r
+ return null;\r
+ return parentVariable.getPossibleChild(graph, name);\r
+ }\r
+\r
+ /**\r
+ * Returns the composite where the connection given as a parameter resides.\r
+ */\r
+ public static Resource getCompositeOfConnection(ReadGraph graph, Resource connection) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+ // First from connected components\r
+ for(Resource component : graph.getObjects(connection, STR.Connects))\r
+ for(Resource composite : graph.getObjects(component, L0.PartOf))\r
+ return composite;\r
+ // It could be that the connection is only supported by joins (input flag -> output flag) - use diagram info TODO!!\r
+ Resource connToDiagramConn = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/ConnectionToDiagramConnection");\r
+ if(connToDiagramConn != null) {\r
+ Resource diagramConnection = graph.getPossibleObject(connection, connToDiagramConn);\r
+ if(diagramConnection != null) {\r
+ Resource diagram = graph.getPossibleObject(diagramConnection, L0.PartOf);\r
+ if(diagram != null) {\r
+ Resource diagramToComposite = graph.getPossibleResource("http://www.simantics.org/Modeling-1.2/DiagramToComposite");\r
+ if(diagramToComposite != null) {\r
+ return graph.getPossibleObject(diagram, diagramToComposite);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ static class Flatten extends BinaryRead<Variable,Resource,Collection<VariableConnectionPointDescriptor>> {\r
+\r
+ public Flatten(Variable parameter1,\r
+ Resource parameter2) {\r
+ super(parameter1, parameter2);\r
+ }\r
+\r
+ @Override\r
+ public Collection<VariableConnectionPointDescriptor> perform(ReadGraph graph)\r
+ throws DatabaseException {\r
+ return doFlatten(graph, parameter, parameter2, null);\r
+ }\r
+ \r
+ }\r
+ \r
+ public static Collection<VariableConnectionPointDescriptor> flatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {\r
+\r
+ if(relationType == null) return graph.syncRequest(new Flatten(child, cp));\r
+\r
+ return doFlatten(graph, child, cp, relationType);\r
+\r
+ }\r
+\r
+ public static Collection<VariableConnectionPointDescriptor> doFlatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException {\r
+ \r
+ Collection<VariableConnectionPointDescriptor> climbed = climb(graph, child, cp, null);\r
+ boolean needDrill = false;\r
+ for(VariableConnectionPointDescriptor desc : climbed) {\r
+ if(!desc.isLeaf(graph)) {\r
+ needDrill = true;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if(!needDrill) {\r
+ if(relationType != null) {\r
+ ArrayList<VariableConnectionPointDescriptor> filtered = new ArrayList<VariableConnectionPointDescriptor>(climbed.size());\r
+ for(VariableConnectionPointDescriptor desc : climbed)\r
+ if(filterByRelationType(graph, desc, relationType))\r
+ filtered.add(desc);\r
+ return filtered;\r
+ }\r
+ return climbed;\r
+ }\r
+ \r
+ THashSet<VariableConnectionPointDescriptor> result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());\r
+ for(VariableConnectionPointDescriptor top : climbed) {\r
+ Collection<VariableConnectionPointDescriptor> drilled = drill(graph, top);\r
+ if(drilled != null) {\r
+ for(VariableConnectionPointDescriptor drill : drilled) {\r
+ if(relationType != null) {\r
+ if(!filterByRelationType(graph, drill, relationType))\r
+ continue;\r
+ }\r
+ result.add(drill);\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ \r
+ }\r
+ \r
+ private static boolean filterByRelationType(ReadGraph graph, VariableConnectionPointDescriptor desc, Resource relationType) throws DatabaseException {\r
+ Resource predicateResource = desc.getConnectionPointResource(graph);\r
+ return predicateResource != null && graph.isInstanceOf(predicateResource, relationType);\r
+ }\r
+\r
+ private static String safeURI(ReadGraph graph, Variable v) {\r
+ if (v == null)\r
+ return "null variable";\r
+ try {\r
+ return v.getURI(graph);\r
+ } catch (DatabaseException e) {\r
+ return v.toString();\r
+ }\r
+ }\r
+}\r