1 /*******************************************************************************
\r
2 * Copyright (c) 2012 Association for Decentralized Information Management in
\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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.flags;
\r
14 import gnu.trove.set.hash.THashSet;
\r
16 import java.util.Collections;
\r
17 import java.util.Set;
\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
37 * @author Hannu Niemistö
\r
38 * @author Tuukka Lehtonen
\r
40 public class LiftFlag {
\r
42 private static final boolean DEBUG = false;
\r
44 public static class LiftedConnectionPoint extends Bean {
\r
46 public Resource component;
\r
48 public Resource componentType;
\r
50 public Resource connectionPoint;
\r
52 * Read through STR.HasAttachmentRelation from configuration connection
\r
56 public Resource attachmentRelation;
\r
60 * Creates a connection point for the flag. Returns null
\r
61 * if the operation succeeded, otherwise returns an error message.
\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
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
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
80 // Find component and connection point
\r
81 LiftedConnectionPoint lcp = calculateLiftedConnectionPointForConnection(g, connection);
\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
89 // Generate default name
\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
95 // Create the connection point
\r
96 Resource connectionPoint = g.newResource();
\r
97 Resource connectionPointInv = g.newResource();
\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
103 for (Resource type : g.getObjects(lcp.connectionPoint, L0.InstanceOf)) {
\r
104 g.claim(connectionPoint, L0.InstanceOf, null, type);
\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
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
121 StructuralUtils.addConnectionPoint(g, lcp.componentType, connectionPoint);
\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
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
132 g.claim(lcp.componentType, L0.ConsistsOf, connectionPoint);
\r
141 * @throws DatabaseException
\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
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
154 Resource mappedConnection = ConnectionUtil.tryGetMappedConnection(g, connector);
\r
155 if(mappedConnection != null) return mappedConnection;
\r
164 * @throws DatabaseException
\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
170 StringBuilder sb = new StringBuilder();
\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
177 sb.append("Lifted").append(cpName);
\r
180 if (cpName == null)
\r
181 sb.append(componentName).append("Lifted");
\r
183 sb.append(componentName).append("_").append(cpName);
\r
186 return sb.toString();
\r
193 * @throws DatabaseException
\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
205 * @param connection
\r
207 * @throws DatabaseException
\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
217 System.out.println("calculateLiftedConnectionPoint from connection: " + NameUtils.getSafeName(graph, connection, true));
\r
219 LiftedConnectionPoint result = new LiftedConnectionPoint();
\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
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
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
235 System.out.println("connector: " + NameUtils.getSafeName(graph, connector, true));
\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
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
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
256 System.out.println("attachmentRelation: " + NameUtils.getSafeName(graph, result.attachmentRelation));
\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
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
275 curComponent = graph.getPossibleObject(curComponent, L0.PartOf);
\r
276 if (curComponent == null)
\r
285 * @param componentType
\r
286 * @param connectionPoint
\r
288 * @return <code>null</code> if connection point is valid
\r
289 * @throws DatabaseException
\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
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
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
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
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
334 * @param componentType
\r
335 * @param connectionPoint
\r
337 * @return <code>null</code> if connection point was properly validated
\r
338 * @throws DatabaseException
\r
340 public static String validateConnectionPoint(WriteGraph graph, Resource componentType, Resource connectionPoint,
\r
341 LiftedConnectionPoint proper) throws DatabaseException {
\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
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
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
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
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
381 * @param properTypes
\r
382 * @throws DatabaseException
\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