]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/flags/LiftFlag.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / flags / LiftFlag.java
1 /*******************************************************************************\r
2  * Copyright (c) 2012 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.flags;\r
13 \r
14 import gnu.trove.set.hash.THashSet;\r
15 \r
16 import java.util.Collections;\r
17 import java.util.Set;\r
18 \r
19 import org.simantics.databoard.Bindings;\r
20 import org.simantics.databoard.annotations.Optional;\r
21 import org.simantics.databoard.util.Bean;\r
22 import org.simantics.db.ReadGraph;\r
23 import org.simantics.db.Resource;\r
24 import org.simantics.db.Statement;\r
25 import org.simantics.db.WriteGraph;\r
26 import org.simantics.db.common.utils.NameUtils;\r
27 import org.simantics.db.exception.DatabaseException;\r
28 import org.simantics.diagram.content.ConnectionUtil;\r
29 import org.simantics.diagram.stubs.DiagramResource;\r
30 import org.simantics.layer0.Layer0;\r
31 import org.simantics.modeling.ModelingResources;\r
32 import org.simantics.structural.stubs.StructuralResource2;\r
33 import org.simantics.structural2.utils.StructuralUtils;\r
34 import org.simantics.utils.ObjectUtils;\r
35 \r
36 /**\r
37  * @author Hannu Niemistö\r
38  * @author Tuukka Lehtonen\r
39  */\r
40 public class LiftFlag {\r
41 \r
42     private static final boolean DEBUG = false;\r
43 \r
44     public static class LiftedConnectionPoint extends Bean {\r
45         @Optional\r
46         public Resource component;\r
47         @Optional\r
48         public Resource componentType;\r
49         @Optional\r
50         public Resource connectionPoint;\r
51         /**\r
52          * Read through STR.HasAttachmentRelation from configuration connection\r
53          * point.\r
54          */\r
55         @Optional\r
56         public Resource attachmentRelation;\r
57     }\r
58 \r
59     /**\r
60      * Creates a connection point for the flag. Returns null\r
61      * if the operation succeeded, otherwise returns an error message.\r
62      */\r
63     public static String liftFlag(WriteGraph g, Resource flag) throws DatabaseException {\r
64         Layer0 L0 = Layer0.getInstance(g);\r
65         StructuralResource2 STR = StructuralResource2.getInstance(g);\r
66         DiagramResource DIA = DiagramResource.getInstance(g);\r
67         ModelingResources MOD = ModelingResources.getInstance(g);\r
68 \r
69         // Check preconditions\r
70         if (g.hasStatement(flag, STR.IsJoinedBy))\r
71             return "Flag is already connected to other flag.";\r
72         if (g.hasStatement(flag, DIA.IsLiftedAs))\r
73             return "Flag is already lifted.";\r
74 \r
75         // Find configuration connection\r
76         Resource connection = findConfigurationConnection(g, flag);\r
77         if (connection == null)\r
78             return "Couldn't find configuration connection.";\r
79 \r
80         // Find component and connection point\r
81         LiftedConnectionPoint lcp = calculateLiftedConnectionPointForConnection(g, connection);\r
82 \r
83         // Validate calculated result\r
84         if (lcp.component == null)\r
85             return "Didn't find a component where the flag is connected to.";\r
86         if (lcp.componentType == null)\r
87             return "Didn't find an enclosing user component.";\r
88 \r
89         // Generate default name\r
90         if (DEBUG)\r
91             System.out.println("found user component : " + NameUtils.getSafeName(g, lcp.componentType, true));\r
92         String newName = generateTerminalName(g, lcp);\r
93         newName = NameUtils.findFreshName(g, newName, lcp.componentType);\r
94 \r
95         // Create the connection point\r
96         Resource connectionPoint = g.newResource();\r
97         Resource connectionPointInv = g.newResource();\r
98 \r
99         for (Resource superrelation : g.getObjects(lcp.connectionPoint, L0.SubrelationOf)) {\r
100             g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);\r
101             g.claim(connectionPointInv, L0.SubrelationOf, null, g.getInverse(superrelation));\r
102         }\r
103         for (Resource type : g.getObjects(lcp.connectionPoint, L0.InstanceOf)) {\r
104             g.claim(connectionPoint, L0.InstanceOf, null, type);\r
105         }\r
106         g.claim(connectionPoint, L0.InverseOf, connectionPointInv);\r
107         g.claimLiteral(connectionPoint, L0.HasName, newName, Bindings.STRING);\r
108         g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);\r
109         g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);\r
110         g.claim(connectionPoint, L0.HasDomain, lcp.componentType);\r
111 \r
112         // Copy custom connection point terminal definitions from referenced\r
113         // lifted connection point. Assertions from types may also bring some\r
114         // definitions in already.\r
115         for (Statement terminalStm : g.getStatements(lcp.connectionPoint, MOD.ConnectionRelationToTerminal)) {\r
116             if (!terminalStm.isAsserted(lcp.connectionPoint)) {\r
117                 g.claim(connectionPoint, MOD.ConnectionRelationToTerminal, terminalStm.getObject());\r
118             }\r
119         }\r
120 \r
121         StructuralUtils.addConnectionPoint(g, lcp.componentType, connectionPoint);\r
122 \r
123         g.claim(flag, DIA.IsLiftedAs, connectionPoint);\r
124         // This is now somewhat redundant, because statement is also added\r
125         // in mapping. But maybe flag is lifted when mapping is not active?\r
126         g.claim(connection, STR.Binds, connectionPoint);\r
127 \r
128         // See platform issue https://www.simantics.org/redmine/issues/3482\r
129         if (lcp.attachmentRelation != null)\r
130             g.claim(connectionPoint, STR.HasAttachmentRelation, lcp.attachmentRelation);\r
131 \r
132         g.claim(lcp.componentType, L0.ConsistsOf, connectionPoint);\r
133 \r
134         return null;\r
135     }\r
136 \r
137     /**\r
138      * @param g\r
139      * @param element\r
140      * @return\r
141      * @throws DatabaseException\r
142      */\r
143     public static Resource findConfigurationConnection(ReadGraph g, Resource element) throws DatabaseException {\r
144         StructuralResource2 STR = StructuralResource2.getInstance(g);\r
145         ModelingResources MOD = ModelingResources.getInstance(g);\r
146 \r
147         for (Resource connector : g.getObjects(element, STR.IsConnectedTo)) {\r
148             Resource diagramConnection = ConnectionUtil.tryGetConnection(g, connector);\r
149             if (diagramConnection != null) {\r
150                 Resource connection = g.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);\r
151                 if (connection != null)\r
152                     return connection;\r
153             }\r
154             Resource mappedConnection = ConnectionUtil.tryGetMappedConnection(g, connector);\r
155             if(mappedConnection != null) return mappedConnection;\r
156         }\r
157         return null;\r
158     }\r
159 \r
160     /**\r
161      * @param g\r
162      * @param lcp\r
163      * @return\r
164      * @throws DatabaseException \r
165      */\r
166     public static String generateTerminalName(ReadGraph g, LiftedConnectionPoint lcp) throws DatabaseException {\r
167         String componentName = NameUtils.getSafeName(g, lcp.component);\r
168         String cpName = NameUtils.getSafeName(g, lcp.connectionPoint);\r
169 \r
170         StringBuilder sb = new StringBuilder();\r
171 \r
172         // NOTE: NameUtils.getSafeName never returns null so part of this logic below is a bit useless.\r
173         if (componentName == null) {\r
174             if (cpName == null)\r
175                 sb.append("ConnectionPoint");\r
176             else\r
177                 sb.append("Lifted").append(cpName);\r
178         }\r
179         else {\r
180             if (cpName == null)\r
181                 sb.append(componentName).append("Lifted");\r
182             else\r
183                 sb.append(componentName).append("_").append(cpName);\r
184         }\r
185 \r
186         return sb.toString();\r
187     }\r
188 \r
189     /**\r
190      * @param graph\r
191      * @param flag\r
192      * @return\r
193      * @throws DatabaseException\r
194      */\r
195     public static LiftedConnectionPoint calculateLiftedConnectionPointForFlag(ReadGraph graph, Resource flag)\r
196             throws DatabaseException {\r
197         Resource connection = findConfigurationConnection(graph, flag);\r
198         return connection == null\r
199                 ? new LiftedConnectionPoint()\r
200                 : calculateLiftedConnectionPointForConnection(graph, connection);\r
201     }\r
202 \r
203     /**\r
204      * @param graph\r
205      * @param connection\r
206      * @return\r
207      * @throws DatabaseException\r
208      */\r
209     public static LiftedConnectionPoint calculateLiftedConnectionPointForConnection(ReadGraph graph, Resource connection)\r
210             throws DatabaseException {\r
211         Layer0 L0 = Layer0.getInstance(graph);\r
212         DiagramResource DIA = DiagramResource.getInstance(graph);\r
213         ModelingResources MOD = ModelingResources.getInstance(graph);\r
214         StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
215 \r
216         if (DEBUG)\r
217             System.out.println("calculateLiftedConnectionPoint from connection: " + NameUtils.getSafeName(graph, connection, true));\r
218 \r
219         LiftedConnectionPoint result = new LiftedConnectionPoint();\r
220 \r
221         findOutputTerminal: for (Statement stat : graph.getStatements(connection, STR.Connects)) {\r
222             result.component = stat.getObject();\r
223             result.connectionPoint = graph.getInverse(stat.getPredicate());\r
224             result.attachmentRelation = graph.getPossibleObject(result.connectionPoint, STR.HasAttachmentRelation);\r
225 \r
226             if (DEBUG)\r
227                 System.out.println("  connection point " + NameUtils.getSafeName(graph, result.connectionPoint, true)\r
228                         + " connects component " + NameUtils.getSafeName(graph, result.component, true)\r
229                         + " with attachment " + NameUtils.getSafeName(graph, result.attachmentRelation));\r
230 \r
231             // This code tries to find component and connector behind signals\r
232             Resource connector = graph.getPossibleObject(result.component, MOD.ComponentToConnector);\r
233             if (connector != null) {\r
234                 if (DEBUG)\r
235                     System.out.println("connector: " + NameUtils.getSafeName(graph, connector, true));\r
236 \r
237                 for (Statement s : graph.getStatements(connector, STR.Connects)) {\r
238                     Resource element = s.getObject();\r
239                     Resource diagramRelation = graph.getInverse(s.getPredicate());\r
240                     Resource componentCandidate = graph.getPossibleObject(element, MOD.ElementToComponent);\r
241                     Resource cpCandidate = graph.getPossibleObject(diagramRelation, MOD.DiagramConnectionRelationToConnectionRelation);\r
242 \r
243                     if (DEBUG) {\r
244                         System.out.println("element: " + NameUtils.getSafeName(graph, element, true));\r
245                         System.out.println("diagram connection relation: " + NameUtils.getSafeName(graph, diagramRelation, true));\r
246                         System.out.println("component candidate: " + NameUtils.getSafeName(graph, componentCandidate, true));\r
247                         System.out.println("connection point candidate: " + NameUtils.getSafeName(graph, cpCandidate, true));\r
248                     }\r
249 \r
250                     if (componentCandidate != null && cpCandidate != null) {\r
251                         result.component = componentCandidate;\r
252                         result.connectionPoint = cpCandidate;\r
253                         result.attachmentRelation = graph.getPossibleObject(cpCandidate, STR.HasAttachmentRelation);\r
254 \r
255                         if (DEBUG)\r
256                             System.out.println("attachmentRelation: " + NameUtils.getSafeName(graph, result.attachmentRelation));\r
257 \r
258                         if (result.attachmentRelation != null\r
259                                 && graph.isSubrelationOf(result.attachmentRelation, DIA.HasTailConnector))\r
260                             // Found an output terminal, this is the one we want.\r
261                             break findOutputTerminal;\r
262                     }\r
263                 }\r
264             }\r
265         }\r
266 \r
267         // Find component type\r
268         Resource componentType = null;\r
269         for (Resource curComponent = result.component; true;) {\r
270             componentType = graph.getPossibleObject(curComponent, STR.Defines);\r
271             if (componentType != null) {\r
272                 result.componentType = componentType;\r
273                 break;\r
274             }\r
275             curComponent = graph.getPossibleObject(curComponent, L0.PartOf);\r
276             if (curComponent == null)\r
277                 break;  \r
278         }\r
279 \r
280         return result;\r
281     }\r
282 \r
283     /**\r
284      * @param graph\r
285      * @param componentType\r
286      * @param connectionPoint\r
287      * @param proper\r
288      * @return <code>null</code> if connection point is valid\r
289      * @throws DatabaseException\r
290      */\r
291     public static String isConnectionPointValid(ReadGraph graph, Resource componentType, Resource connectionPoint,\r
292             LiftedConnectionPoint proper) throws DatabaseException {\r
293         Layer0 L0 = Layer0.getInstance(graph);\r
294         DiagramResource DIA = DiagramResource.getInstance(graph);\r
295         ModelingResources MOD = ModelingResources.getInstance(graph);\r
296         StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
297 \r
298         Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);\r
299         if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation))\r
300             return "Wrong connection point (" + connectionPoint + ") attachment relation: is " + existingHasAttachment\r
301                     + ", should be " + proper.attachmentRelation;\r
302 \r
303         {\r
304             Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, L0.InstanceOf));\r
305             Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null\r
306                     ? graph.getObjects(proper.connectionPoint, L0.InstanceOf)\r
307                             : Collections.<Resource>emptySet());\r
308             if (!existingTypes.equals(properTypes))\r
309                 return "Incorrect connection point relation (" + connectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
310         }\r
311 \r
312         Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);\r
313         if (diagramConnectionPoint != null) {\r
314             Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(diagramConnectionPoint, L0.InstanceOf));\r
315             Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null\r
316                     ? graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType)\r
317                             : Collections.<Resource>emptySet());\r
318             if (!existingTypes.equals(properTypes))\r
319                 return "Incorrect diagram connection point relation (" + diagramConnectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
320 \r
321             Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));\r
322             for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
323                 Set<Resource> existingTerminalTypes = new THashSet<Resource>(graph.getObjects(terminal, L0.InstanceOf));\r
324                 if (!existingTerminalTypes.equals(properTerminalTypes))\r
325                     return "Incorrect diagram connection point relation types (existing " + existingTypes + " vs. proper " + properTypes + ")";\r
326             }\r
327         }\r
328 \r
329         return null;\r
330     }\r
331 \r
332     /**\r
333      * @param graph\r
334      * @param componentType\r
335      * @param connectionPoint\r
336      * @param proper\r
337      * @return <code>null</code> if connection point was properly validated\r
338      * @throws DatabaseException\r
339      */\r
340     public static String validateConnectionPoint(WriteGraph graph, Resource componentType, Resource connectionPoint,\r
341             LiftedConnectionPoint proper) throws DatabaseException {\r
342 \r
343         Layer0 L0 = Layer0.getInstance(graph);\r
344         DiagramResource DIA = DiagramResource.getInstance(graph);\r
345         ModelingResources MOD = ModelingResources.getInstance(graph);\r
346         StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
347 \r
348         // Fix HasAttachmentRelation of connectionPoint\r
349         Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);\r
350         if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation)) {\r
351             graph.deny(connectionPoint, STR.HasAttachmentRelation);\r
352             if (proper.attachmentRelation != null)\r
353                 graph.claim(connectionPoint, STR.HasAttachmentRelation, proper.attachmentRelation);\r
354         }\r
355 \r
356         // Fix InstanceOf's of connectionPoint\r
357         fixDirectTypes(graph, connectionPoint, proper.connectionPoint != null\r
358                 ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, L0.InstanceOf) )\r
359                         : Collections.<Resource>emptySet());\r
360 \r
361         // Fix InstanceOf's of connection point's diagram connection relation\r
362         Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);\r
363         if (diagramConnectionPoint != null) {\r
364             fixDirectTypes(graph, diagramConnectionPoint, proper.connectionPoint != null\r
365                     ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType) )\r
366                             : Collections.<Resource>emptySet());\r
367 \r
368             // Fix InstanceOf's of connection point's diagram connection relation's symbol terminal\r
369             Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));\r
370             for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
371                 fixDirectTypes(graph, terminal, properTerminalTypes);\r
372             }\r
373         }\r
374 \r
375         return null;\r
376     }\r
377 \r
378     /**\r
379      * @param graph\r
380      * @param r\r
381      * @param properTypes\r
382      * @throws DatabaseException\r
383      */\r
384     private static void fixDirectTypes(WriteGraph graph, Resource r, Set<Resource> properTypes) throws DatabaseException {\r
385         Layer0 L0 = Layer0.getInstance(graph);\r
386         Set<Resource> existingTypes = new THashSet<Resource>( graph.getObjects(r, L0.InstanceOf) );\r
387         if (!existingTypes.equals(properTypes)) {\r
388             Set<Resource> addTypes = new THashSet<Resource>(properTypes);\r
389             properTypes.removeAll(existingTypes);\r
390             existingTypes.removeAll(properTypes);\r
391             for (Resource remove : existingTypes)\r
392                 graph.deny(r, L0.InstanceOf, remove);\r
393             for (Resource add : addTypes)\r
394                 graph.claim(r, L0.InstanceOf, null, add);\r
395         }\r
396     }\r
397 \r
398 }\r