-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 gnu.trove.map.hash.THashMap;
+import gnu.trove.set.hash.THashSet;
+
+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.variables.StandardProceduralChildVariable.FixedConnection;
+import org.simantics.utils.datastructures.Pair;
+
+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 = graph.getPossibleObject(component, L0.InstanceOf);
+ 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 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();
+ 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>();
+ result.add(new ActualConnectionDescriptor(parameter, component, connectionPoint));
+ }
+ }
+ 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 {
+
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+ if(graph.isInstanceOf(resource, STR.ProceduralComponentType)) return false;
+ if(graph.hasStatement(resource, STR.IsDefinedBy)) return false;
+
+ return true;
+
+ }
+
+ }
+
+ 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 {
+
+ Collection<VariableConnectionPointDescriptor> climbed = climb(graph, child, cp, null);
+ boolean needDrill = false;
+ for(VariableConnectionPointDescriptor desc : climbed) {
+ if(!desc.isLeaf(graph)) {
+ needDrill = true;
+ break;
+ }
+ }
+
+ if(!needDrill) {
+ 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;
+ }
+ return climbed;
+ }
+
+ THashSet<VariableConnectionPointDescriptor> result = new THashSet<VariableConnectionPointDescriptor>(climbed.size());
+ for(VariableConnectionPointDescriptor top : climbed) {
+ Collection<VariableConnectionPointDescriptor> drilled = drill(graph, top);
+ if(drilled != null) {
+ for(VariableConnectionPointDescriptor drill : drilled) {
+ if(relationType != null) {
+ if(!filterByRelationType(graph, drill, relationType))
+ continue;
+ }
+ 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();
+ }
+ }
+}