--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.flags;\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.Collections;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.databoard.annotations.Optional;\r
+import org.simantics.databoard.util.Bean;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.utils.StructuralUtils;\r
+import org.simantics.utils.ObjectUtils;\r
+\r
+/**\r
+ * @author Hannu Niemistö\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class LiftFlag {\r
+\r
+ private static final boolean DEBUG = false;\r
+\r
+ public static class LiftedConnectionPoint extends Bean {\r
+ @Optional\r
+ public Resource component;\r
+ @Optional\r
+ public Resource componentType;\r
+ @Optional\r
+ public Resource connectionPoint;\r
+ /**\r
+ * Read through STR.HasAttachmentRelation from configuration connection\r
+ * point.\r
+ */\r
+ @Optional\r
+ public Resource attachmentRelation;\r
+ }\r
+\r
+ /**\r
+ * Creates a connection point for the flag. Returns null\r
+ * if the operation succeeded, otherwise returns an error message.\r
+ */\r
+ public static String liftFlag(WriteGraph g, Resource flag) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(g);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+ DiagramResource DIA = DiagramResource.getInstance(g);\r
+ ModelingResources MOD = ModelingResources.getInstance(g);\r
+\r
+ // Check preconditions\r
+ if (g.hasStatement(flag, STR.IsJoinedBy))\r
+ return "Flag is already connected to other flag.";\r
+ if (g.hasStatement(flag, DIA.IsLiftedAs))\r
+ return "Flag is already lifted.";\r
+\r
+ // Find configuration connection\r
+ Resource connection = findConfigurationConnection(g, flag);\r
+ if (connection == null)\r
+ return "Couldn't find configuration connection.";\r
+\r
+ // Find component and connection point\r
+ LiftedConnectionPoint lcp = calculateLiftedConnectionPointForConnection(g, connection);\r
+\r
+ // Validate calculated result\r
+ if (lcp.component == null)\r
+ return "Didn't find a component where the flag is connected to.";\r
+ if (lcp.componentType == null)\r
+ return "Didn't find an enclosing user component.";\r
+\r
+ // Generate default name\r
+ if (DEBUG)\r
+ System.out.println("found user component : " + NameUtils.getSafeName(g, lcp.componentType, true));\r
+ String newName = generateTerminalName(g, lcp);\r
+ newName = NameUtils.findFreshName(g, newName, lcp.componentType);\r
+\r
+ // Create the connection point\r
+ Resource connectionPoint = g.newResource();\r
+ Resource connectionPointInv = g.newResource();\r
+\r
+ for (Resource superrelation : g.getObjects(lcp.connectionPoint, L0.SubrelationOf)) {\r
+ g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);\r
+ g.claim(connectionPointInv, L0.SubrelationOf, null, g.getInverse(superrelation));\r
+ }\r
+ for (Resource type : g.getObjects(lcp.connectionPoint, L0.InstanceOf)) {\r
+ g.claim(connectionPoint, L0.InstanceOf, null, type);\r
+ }\r
+ g.claim(connectionPoint, L0.InverseOf, connectionPointInv);\r
+ g.claimLiteral(connectionPoint, L0.HasName, newName, Bindings.STRING);\r
+ g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);\r
+ g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);\r
+ g.claim(connectionPoint, L0.HasDomain, lcp.componentType);\r
+\r
+ // Copy custom connection point terminal definitions from referenced\r
+ // lifted connection point. Assertions from types may also bring some\r
+ // definitions in already.\r
+ for (Statement terminalStm : g.getStatements(lcp.connectionPoint, MOD.ConnectionRelationToTerminal)) {\r
+ if (!terminalStm.isAsserted(lcp.connectionPoint)) {\r
+ g.claim(connectionPoint, MOD.ConnectionRelationToTerminal, terminalStm.getObject());\r
+ }\r
+ }\r
+\r
+ StructuralUtils.addConnectionPoint(g, lcp.componentType, connectionPoint);\r
+\r
+ g.claim(flag, DIA.IsLiftedAs, connectionPoint);\r
+ // This is now somewhat redundant, because statement is also added\r
+ // in mapping. But maybe flag is lifted when mapping is not active?\r
+ g.claim(connection, STR.Binds, connectionPoint);\r
+\r
+ // See platform issue https://www.simantics.org/redmine/issues/3482\r
+ if (lcp.attachmentRelation != null)\r
+ g.claim(connectionPoint, STR.HasAttachmentRelation, lcp.attachmentRelation);\r
+\r
+ g.claim(lcp.componentType, L0.ConsistsOf, connectionPoint);\r
+\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @param g\r
+ * @param element\r
+ * @return\r
+ * @throws DatabaseException\r
+ */\r
+ public static Resource findConfigurationConnection(ReadGraph g, Resource element) throws DatabaseException {\r
+ StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+ ModelingResources MOD = ModelingResources.getInstance(g);\r
+\r
+ for (Resource connector : g.getObjects(element, STR.IsConnectedTo)) {\r
+ Resource diagramConnection = ConnectionUtil.tryGetConnection(g, connector);\r
+ if (diagramConnection != null) {\r
+ Resource connection = g.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);\r
+ if (connection != null)\r
+ return connection;\r
+ }\r
+ Resource mappedConnection = ConnectionUtil.tryGetMappedConnection(g, connector);\r
+ if(mappedConnection != null) return mappedConnection;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @param g\r
+ * @param lcp\r
+ * @return\r
+ * @throws DatabaseException \r
+ */\r
+ public static String generateTerminalName(ReadGraph g, LiftedConnectionPoint lcp) throws DatabaseException {\r
+ String componentName = NameUtils.getSafeName(g, lcp.component);\r
+ String cpName = NameUtils.getSafeName(g, lcp.connectionPoint);\r
+\r
+ StringBuilder sb = new StringBuilder();\r
+\r
+ // NOTE: NameUtils.getSafeName never returns null so part of this logic below is a bit useless.\r
+ if (componentName == null) {\r
+ if (cpName == null)\r
+ sb.append("ConnectionPoint");\r
+ else\r
+ sb.append("Lifted").append(cpName);\r
+ }\r
+ else {\r
+ if (cpName == null)\r
+ sb.append(componentName).append("Lifted");\r
+ else\r
+ sb.append(componentName).append("_").append(cpName);\r
+ }\r
+\r
+ return sb.toString();\r
+ }\r
+\r
+ /**\r
+ * @param graph\r
+ * @param flag\r
+ * @return\r
+ * @throws DatabaseException\r
+ */\r
+ public static LiftedConnectionPoint calculateLiftedConnectionPointForFlag(ReadGraph graph, Resource flag)\r
+ throws DatabaseException {\r
+ Resource connection = findConfigurationConnection(graph, flag);\r
+ return connection == null\r
+ ? new LiftedConnectionPoint()\r
+ : calculateLiftedConnectionPointForConnection(graph, connection);\r
+ }\r
+\r
+ /**\r
+ * @param graph\r
+ * @param connection\r
+ * @return\r
+ * @throws DatabaseException\r
+ */\r
+ public static LiftedConnectionPoint calculateLiftedConnectionPointForConnection(ReadGraph graph, Resource connection)\r
+ throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ if (DEBUG)\r
+ System.out.println("calculateLiftedConnectionPoint from connection: " + NameUtils.getSafeName(graph, connection, true));\r
+\r
+ LiftedConnectionPoint result = new LiftedConnectionPoint();\r
+\r
+ findOutputTerminal: for (Statement stat : graph.getStatements(connection, STR.Connects)) {\r
+ result.component = stat.getObject();\r
+ result.connectionPoint = graph.getInverse(stat.getPredicate());\r
+ result.attachmentRelation = graph.getPossibleObject(result.connectionPoint, STR.HasAttachmentRelation);\r
+\r
+ if (DEBUG)\r
+ System.out.println(" connection point " + NameUtils.getSafeName(graph, result.connectionPoint, true)\r
+ + " connects component " + NameUtils.getSafeName(graph, result.component, true)\r
+ + " with attachment " + NameUtils.getSafeName(graph, result.attachmentRelation));\r
+\r
+ // This code tries to find component and connector behind signals\r
+ Resource connector = graph.getPossibleObject(result.component, MOD.ComponentToConnector);\r
+ if (connector != null) {\r
+ if (DEBUG)\r
+ System.out.println("connector: " + NameUtils.getSafeName(graph, connector, true));\r
+\r
+ for (Statement s : graph.getStatements(connector, STR.Connects)) {\r
+ Resource element = s.getObject();\r
+ Resource diagramRelation = graph.getInverse(s.getPredicate());\r
+ Resource componentCandidate = graph.getPossibleObject(element, MOD.ElementToComponent);\r
+ Resource cpCandidate = graph.getPossibleObject(diagramRelation, MOD.DiagramConnectionRelationToConnectionRelation);\r
+\r
+ if (DEBUG) {\r
+ System.out.println("element: " + NameUtils.getSafeName(graph, element, true));\r
+ System.out.println("diagram connection relation: " + NameUtils.getSafeName(graph, diagramRelation, true));\r
+ System.out.println("component candidate: " + NameUtils.getSafeName(graph, componentCandidate, true));\r
+ System.out.println("connection point candidate: " + NameUtils.getSafeName(graph, cpCandidate, true));\r
+ }\r
+\r
+ if (componentCandidate != null && cpCandidate != null) {\r
+ result.component = componentCandidate;\r
+ result.connectionPoint = cpCandidate;\r
+ result.attachmentRelation = graph.getPossibleObject(cpCandidate, STR.HasAttachmentRelation);\r
+\r
+ if (DEBUG)\r
+ System.out.println("attachmentRelation: " + NameUtils.getSafeName(graph, result.attachmentRelation));\r
+\r
+ if (result.attachmentRelation != null\r
+ && graph.isSubrelationOf(result.attachmentRelation, DIA.HasTailConnector))\r
+ // Found an output terminal, this is the one we want.\r
+ break findOutputTerminal;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Find component type\r
+ Resource componentType = null;\r
+ for (Resource curComponent = result.component; true;) {\r
+ componentType = graph.getPossibleObject(curComponent, STR.Defines);\r
+ if (componentType != null) {\r
+ result.componentType = componentType;\r
+ break;\r
+ }\r
+ curComponent = graph.getPossibleObject(curComponent, L0.PartOf);\r
+ if (curComponent == null)\r
+ break; \r
+ }\r
+\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * @param graph\r
+ * @param componentType\r
+ * @param connectionPoint\r
+ * @param proper\r
+ * @return <code>null</code> if connection point is valid\r
+ * @throws DatabaseException\r
+ */\r
+ public static String isConnectionPointValid(ReadGraph graph, Resource componentType, Resource connectionPoint,\r
+ LiftedConnectionPoint proper) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);\r
+ if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation))\r
+ return "Wrong connection point (" + connectionPoint + ") attachment relation: is " + existingHasAttachment\r
+ + ", should be " + proper.attachmentRelation;\r
+\r
+ {\r
+ Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, L0.InstanceOf));\r
+ Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null\r
+ ? graph.getObjects(proper.connectionPoint, L0.InstanceOf)\r
+ : Collections.<Resource>emptySet());\r
+ if (!existingTypes.equals(properTypes))\r
+ return "Incorrect connection point relation (" + connectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
+ }\r
+\r
+ Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);\r
+ if (diagramConnectionPoint != null) {\r
+ Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(diagramConnectionPoint, L0.InstanceOf));\r
+ Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null\r
+ ? graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType)\r
+ : Collections.<Resource>emptySet());\r
+ if (!existingTypes.equals(properTypes))\r
+ return "Incorrect diagram connection point relation (" + diagramConnectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
+\r
+ Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));\r
+ for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
+ Set<Resource> existingTerminalTypes = new THashSet<Resource>(graph.getObjects(terminal, L0.InstanceOf));\r
+ if (!existingTerminalTypes.equals(properTerminalTypes))\r
+ return "Incorrect diagram connection point relation types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @param graph\r
+ * @param componentType\r
+ * @param connectionPoint\r
+ * @param proper\r
+ * @return <code>null</code> if connection point was properly validated\r
+ * @throws DatabaseException\r
+ */\r
+ public static String validateConnectionPoint(WriteGraph graph, Resource componentType, Resource connectionPoint,\r
+ LiftedConnectionPoint proper) throws DatabaseException {\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ // Fix HasAttachmentRelation of connectionPoint\r
+ Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);\r
+ if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation)) {\r
+ graph.deny(connectionPoint, STR.HasAttachmentRelation);\r
+ if (proper.attachmentRelation != null)\r
+ graph.claim(connectionPoint, STR.HasAttachmentRelation, proper.attachmentRelation);\r
+ }\r
+\r
+ // Fix InstanceOf's of connectionPoint\r
+ fixDirectTypes(graph, connectionPoint, proper.connectionPoint != null\r
+ ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, L0.InstanceOf) )\r
+ : Collections.<Resource>emptySet());\r
+\r
+ // Fix InstanceOf's of connection point's diagram connection relation\r
+ Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);\r
+ if (diagramConnectionPoint != null) {\r
+ fixDirectTypes(graph, diagramConnectionPoint, proper.connectionPoint != null\r
+ ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType) )\r
+ : Collections.<Resource>emptySet());\r
+\r
+ // Fix InstanceOf's of connection point's diagram connection relation's symbol terminal\r
+ Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));\r
+ for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
+ fixDirectTypes(graph, terminal, properTerminalTypes);\r
+ }\r
+ }\r
+\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @param graph\r
+ * @param r\r
+ * @param properTypes\r
+ * @throws DatabaseException\r
+ */\r
+ private static void fixDirectTypes(WriteGraph graph, Resource r, Set<Resource> properTypes) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ Set<Resource> existingTypes = new THashSet<Resource>( graph.getObjects(r, L0.InstanceOf) );\r
+ if (!existingTypes.equals(properTypes)) {\r
+ Set<Resource> addTypes = new THashSet<Resource>(properTypes);\r
+ properTypes.removeAll(existingTypes);\r
+ existingTypes.removeAll(properTypes);\r
+ for (Resource remove : existingTypes)\r
+ graph.deny(r, L0.InstanceOf, remove);\r
+ for (Resource add : addTypes)\r
+ graph.claim(r, L0.InstanceOf, null, add);\r
+ }\r
+ }\r
+\r
+}\r