]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / variables / ConnectionBrowser.java
diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java
new file mode 100644 (file)
index 0000000..d1ec55f
--- /dev/null
@@ -0,0 +1,645 @@
+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