X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.structural2%2Fsrc%2Forg%2Fsimantics%2Fstructural2%2Fvariables%2FConnectionBrowser.java;fp=bundles%2Forg.simantics.structural2%2Fsrc%2Forg%2Fsimantics%2Fstructural2%2Fvariables%2FConnectionBrowser.java;h=d1ec55f6d898b31c743ffc6fbbedc3c699c798f6;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java new file mode 100644 index 000000000..d1ec55f6d --- /dev/null +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/variables/ConnectionBrowser.java @@ -0,0 +1,645 @@ +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 findConnectedComponents( + ReadGraph graph, Resource connection, Variable configuration) + throws DatabaseException { + // Create state + ArrayList result = + new ArrayList(); + THashSet visitedConnections = new THashSet(); + + // Do actual work + findConnectedComponents(graph, connection, configuration, result, + visitedConnections); + return result; + } + + private static void findConnectedComponents( + ReadGraph graph, Resource connection, Variable configuration, + ArrayList result, + THashSet 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 drill(ReadGraph graph, VariableConnectionPointDescriptor pair) throws DatabaseException { + + Collection 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 result = new ArrayList(); + 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> { + + public JoinConnections(Resource join) { + super(join); + } + + @Override + public Collection perform(ReadGraph graph) throws DatabaseException { + ConnectionSet cs = new ConnectionSet(graph); + cs.addJoin(graph, resource); + return cs.getConnections(); + } + + } + + + public static final class VariableChildren extends TransientUnaryRead> { + + 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 perform(ReadGraph graph, Variable parameter) throws DatabaseException { + CollectionSupport cs = graph.getService(CollectionSupport.class); + Map 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 map = graph.syncRequest(new VariableChildren(graph, base), TransientCacheAsyncListener.>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.>instance()); + return map.get(component); + } + } + + public static class ConnectionComponentsWithAncestor extends TransientUnaryRead> { + + final private List result; + + public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn) throws DatabaseException { + this(graph, conn, null); + } + + public ConnectionComponentsWithAncestor(ReadGraph graph, QueryControl qc, Resource conn, List result) throws DatabaseException { + super(graph, qc, conn); + this.result = result; + } + + public ConnectionComponentsWithAncestor(ReadGraph graph, Resource conn, List 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 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 ancestorGenerators = new THashSet(); + Set 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 result = colls.createList(); + result.add(ancestor); + result.addAll(colls.asSortedList(parts)); + + if(parameter != WITH_PARENT) { + for(int i=1;i>instance()); + } + } + + return result; + + } + + } + + public static Collection climb(ReadGraph graph, Variable child, Resource cp, String subPath_) throws DatabaseException { + + boolean isStructural = false; + + Variable curConfiguration = child.getParent(graph); + + { + + Collection 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 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 result = new THashSet(1+fc.cps.size()); + result.add(new ComponentConnectionDescriptor(child, cp));// (graph, STR, curConfiguration, "/" + c.name + "#" + conn.getName(graph))); + for(Pair 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 conns = graph.getObjects(represents, res); + HashSet result = new HashSet(); + for(Resource c : conns) { + List rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.>instance()); + result.addAll(graph.syncRequest(ConnectionVariables.forStructural(graph, curConfiguration, rs))); + } + return result; + + } else { + + Resource connection = graph.getPossibleObject(represents, res); + if(connection != null) { + List rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, connection), TransientCacheAsyncListener.>instance()); + return graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs)); + } + else { + Collection conns = graph.getObjects(represents, res); + HashSet result = new HashSet(); + for(Resource c : conns) { + List rs = graph.syncRequest(new ConnectionComponentsWithAncestor(graph, c), TransientCacheAsyncListener.>instance()); + result.addAll(graph.syncRequest(ConnectionVariables.forConfiguration(graph, curConfiguration, rs))); + } + return result; + } + + } + + } + + } + + public static class ConnectionVariables extends BinaryRead, Collection> { + + private ConnectionVariables(Variable parameter1, List parameter2) { + super(parameter1, parameter2); + } + + public static ConnectionVariables forConfiguration(ReadGraph graph, Variable configuration, List rs) throws DatabaseException { + return new ConnectionVariables(parent(graph, configuration, rs.get(0)), rs); + } + + public static ConnectionVariables forStructural(ReadGraph graph, Variable configuration, List rs) throws DatabaseException { + return new ConnectionVariables(configuration, rs); + } + + /** + * Finds the parent variable of configuration that + * represents ancestor. + * + * @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 perform(ReadGraph graph) throws DatabaseException { + if(parameter == null) return Collections.emptyList(); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + ArrayList result = null; + for(int i=1;i(); + result.add(new ActualConnectionDescriptor(parameter, component, connectionPoint)); + } + } + if(result == null) return Collections.emptyList(); + return result; + } + + } + + static class IsLeafType extends ResourceRead { + + 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> { + + public ChildMapOfVariable(Variable variable) { + super(variable); + } + + @Override + public Map perform(ReadGraph graph) throws DatabaseException { + HashMap result = new HashMap(); + 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: + *
+     *     URI(source)        = resourceURIBase + sourceSuffix
+     *     URI(sourceContext) = variableURIBase + sourceSuffix
+     *     URI(target)        = resourceURIBase + targetSuffix
+     *     URI(targetContext) = variableURIBase + targetSuffix
+     * 
+ */ + public static Variable browseSibling(ReadGraph graph, Resource source, Variable sourceContext, Resource target) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + THashMap sourceMap = new THashMap(); + 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 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> { + + public Flatten(Variable parameter1, + Resource parameter2) { + super(parameter1, parameter2); + } + + @Override + public Collection perform(ReadGraph graph) + throws DatabaseException { + return doFlatten(graph, parameter, parameter2, null); + } + + } + + public static Collection 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 doFlatten(ReadGraph graph, Variable child, Resource cp, Resource relationType) throws DatabaseException { + + Collection 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 filtered = new ArrayList(climbed.size()); + for(VariableConnectionPointDescriptor desc : climbed) + if(filterByRelationType(graph, desc, relationType)) + filtered.add(desc); + return filtered; + } + return climbed; + } + + THashSet result = new THashSet(climbed.size()); + for(VariableConnectionPointDescriptor top : climbed) { + Collection 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(); + } + } +}