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