1 /*******************************************************************************
2 * Copyright (c) 2012 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.modeling.flags;
14 import gnu.trove.set.hash.THashSet;
16 import java.util.Collections;
19 import org.simantics.databoard.Bindings;
20 import org.simantics.databoard.annotations.Optional;
21 import org.simantics.databoard.util.Bean;
22 import org.simantics.db.ReadGraph;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Statement;
25 import org.simantics.db.WriteGraph;
26 import org.simantics.db.common.utils.NameUtils;
27 import org.simantics.db.exception.DatabaseException;
28 import org.simantics.diagram.content.ConnectionUtil;
29 import org.simantics.diagram.stubs.DiagramResource;
30 import org.simantics.layer0.Layer0;
31 import org.simantics.modeling.ModelingResources;
32 import org.simantics.structural.stubs.StructuralResource2;
33 import org.simantics.structural2.utils.StructuralUtils;
34 import org.simantics.utils.ObjectUtils;
37 * @author Hannu Niemistö
38 * @author Tuukka Lehtonen
40 public class LiftFlag {
42 private static final boolean DEBUG = false;
44 public static class LiftedConnectionPoint extends Bean {
46 public Resource component;
48 public Resource componentType;
50 public Resource connectionPoint;
52 * Read through STR.HasAttachmentRelation from configuration connection
56 public Resource attachmentRelation;
60 * Creates a connection point for the flag. Returns null
61 * if the operation succeeded, otherwise returns an error message.
63 public static String liftFlag(WriteGraph g, Resource flag) throws DatabaseException {
64 Layer0 L0 = Layer0.getInstance(g);
65 StructuralResource2 STR = StructuralResource2.getInstance(g);
66 DiagramResource DIA = DiagramResource.getInstance(g);
67 ModelingResources MOD = ModelingResources.getInstance(g);
69 // Check preconditions
70 if (g.hasStatement(flag, STR.IsJoinedBy))
71 return "Flag is already connected to other flag.";
72 if (g.hasStatement(flag, DIA.IsLiftedAs))
73 return "Flag is already lifted.";
75 // Find configuration connection
76 Resource connection = findConfigurationConnection(g, flag);
77 if (connection == null)
78 return "Couldn't find configuration connection.";
80 // Find component and connection point
81 LiftedConnectionPoint lcp = calculateLiftedConnectionPointForConnection(g, connection);
83 // Validate calculated result
84 if (lcp.component == null)
85 return "Didn't find a component where the flag is connected to.";
86 if (lcp.componentType == null)
87 return "Didn't find an enclosing user component.";
89 // Generate default name
91 System.out.println("found user component : " + NameUtils.getSafeName(g, lcp.componentType, true));
92 String newName = generateTerminalName(g, lcp);
93 newName = NameUtils.findFreshName(g, newName, lcp.componentType);
95 // Create the connection point
96 Resource connectionPoint = g.newResource();
97 Resource connectionPointInv = g.newResource();
99 for (Resource superrelation : g.getObjects(lcp.connectionPoint, L0.SubrelationOf)) {
100 g.claim(connectionPoint, L0.SubrelationOf, null, superrelation);
101 g.claim(connectionPointInv, L0.SubrelationOf, null, g.getInverse(superrelation));
103 for (Resource type : g.getObjects(lcp.connectionPoint, L0.InstanceOf)) {
104 g.claim(connectionPoint, L0.InstanceOf, null, type);
106 g.claim(connectionPoint, L0.InverseOf, connectionPointInv);
107 g.claimLiteral(connectionPoint, L0.HasName, newName, Bindings.STRING);
108 g.claim(connectionPoint, L0.ConsistsOf, connectionPointInv);
109 g.claimLiteral(connectionPointInv, L0.HasName, "Inverse", Bindings.STRING);
110 g.claim(connectionPoint, L0.HasDomain, lcp.componentType);
112 // Copy custom connection point terminal definitions from referenced
113 // lifted connection point. Assertions from types may also bring some
114 // definitions in already.
115 for (Statement terminalStm : g.getStatements(lcp.connectionPoint, MOD.ConnectionRelationToTerminal)) {
116 if (!terminalStm.isAsserted(lcp.connectionPoint)) {
117 g.claim(connectionPoint, MOD.ConnectionRelationToTerminal, terminalStm.getObject());
121 StructuralUtils.addConnectionPoint(g, lcp.componentType, connectionPoint);
123 g.claim(flag, DIA.IsLiftedAs, connectionPoint);
124 // This is now somewhat redundant, because statement is also added
125 // in mapping. But maybe flag is lifted when mapping is not active?
126 g.claim(connection, STR.Binds, connectionPoint);
128 // See platform issue https://www.simantics.org/redmine/issues/3482
129 if (lcp.attachmentRelation != null)
130 g.claim(connectionPoint, STR.HasAttachmentRelation, lcp.attachmentRelation);
132 g.claim(lcp.componentType, L0.ConsistsOf, connectionPoint);
141 * @throws DatabaseException
143 public static Resource findConfigurationConnection(ReadGraph g, Resource element) throws DatabaseException {
144 StructuralResource2 STR = StructuralResource2.getInstance(g);
145 ModelingResources MOD = ModelingResources.getInstance(g);
147 for (Resource connector : g.getObjects(element, STR.IsConnectedTo)) {
148 Resource diagramConnection = ConnectionUtil.tryGetConnection(g, connector);
149 if (diagramConnection != null) {
150 Resource connection = g.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
151 if (connection != null)
154 Resource mappedConnection = ConnectionUtil.tryGetMappedConnection(g, connector);
155 if(mappedConnection != null) return mappedConnection;
164 * @throws DatabaseException
166 public static String generateTerminalName(ReadGraph g, LiftedConnectionPoint lcp) throws DatabaseException {
167 String componentName = NameUtils.getSafeName(g, lcp.component);
168 String cpName = NameUtils.getSafeName(g, lcp.connectionPoint);
170 StringBuilder sb = new StringBuilder();
172 // NOTE: NameUtils.getSafeName never returns null so part of this logic below is a bit useless.
173 if (componentName == null) {
175 sb.append("ConnectionPoint");
177 sb.append("Lifted").append(cpName);
181 sb.append(componentName).append("Lifted");
183 sb.append(componentName).append("_").append(cpName);
186 return sb.toString();
193 * @throws DatabaseException
195 public static LiftedConnectionPoint calculateLiftedConnectionPointForFlag(ReadGraph graph, Resource flag)
196 throws DatabaseException {
197 Resource connection = findConfigurationConnection(graph, flag);
198 return connection == null
199 ? new LiftedConnectionPoint()
200 : calculateLiftedConnectionPointForConnection(graph, connection);
207 * @throws DatabaseException
209 public static LiftedConnectionPoint calculateLiftedConnectionPointForConnection(ReadGraph graph, Resource connection)
210 throws DatabaseException {
211 Layer0 L0 = Layer0.getInstance(graph);
212 DiagramResource DIA = DiagramResource.getInstance(graph);
213 ModelingResources MOD = ModelingResources.getInstance(graph);
214 StructuralResource2 STR = StructuralResource2.getInstance(graph);
217 System.out.println("calculateLiftedConnectionPoint from connection: " + NameUtils.getSafeName(graph, connection, true));
219 LiftedConnectionPoint result = new LiftedConnectionPoint();
221 findOutputTerminal: for (Statement stat : graph.getStatements(connection, STR.Connects)) {
222 result.component = stat.getObject();
223 result.connectionPoint = graph.getInverse(stat.getPredicate());
224 result.attachmentRelation = graph.getPossibleObject(result.connectionPoint, STR.HasAttachmentRelation);
227 System.out.println(" connection point " + NameUtils.getSafeName(graph, result.connectionPoint, true)
228 + " connects component " + NameUtils.getSafeName(graph, result.component, true)
229 + " with attachment " + NameUtils.getSafeName(graph, result.attachmentRelation));
231 // This code tries to find component and connector behind signals
232 Resource connector = graph.getPossibleObject(result.component, MOD.ComponentToConnector);
233 if (connector != null) {
235 System.out.println("connector: " + NameUtils.getSafeName(graph, connector, true));
237 for (Statement s : graph.getStatements(connector, STR.Connects)) {
238 Resource element = s.getObject();
239 Resource diagramRelation = graph.getInverse(s.getPredicate());
240 Resource componentCandidate = graph.getPossibleObject(element, MOD.ElementToComponent);
241 Resource cpCandidate = graph.getPossibleObject(diagramRelation, MOD.DiagramConnectionRelationToConnectionRelation);
244 System.out.println("element: " + NameUtils.getSafeName(graph, element, true));
245 System.out.println("diagram connection relation: " + NameUtils.getSafeName(graph, diagramRelation, true));
246 System.out.println("component candidate: " + NameUtils.getSafeName(graph, componentCandidate, true));
247 System.out.println("connection point candidate: " + NameUtils.getSafeName(graph, cpCandidate, true));
250 if (componentCandidate != null && cpCandidate != null) {
251 result.component = componentCandidate;
252 result.connectionPoint = cpCandidate;
253 result.attachmentRelation = graph.getPossibleObject(cpCandidate, STR.HasAttachmentRelation);
256 System.out.println("attachmentRelation: " + NameUtils.getSafeName(graph, result.attachmentRelation));
258 if (result.attachmentRelation != null
259 && graph.isSubrelationOf(result.attachmentRelation, DIA.HasTailConnector))
260 // Found an output terminal, this is the one we want.
261 break findOutputTerminal;
267 // Find component type
268 Resource componentType = null;
269 for (Resource curComponent = result.component; true;) {
270 componentType = graph.getPossibleObject(curComponent, STR.Defines);
271 if (componentType != null) {
272 result.componentType = componentType;
275 curComponent = graph.getPossibleObject(curComponent, L0.PartOf);
276 if (curComponent == null)
285 * @param componentType
286 * @param connectionPoint
288 * @return <code>null</code> if connection point is valid
289 * @throws DatabaseException
291 public static String isConnectionPointValid(ReadGraph graph, Resource componentType, Resource connectionPoint,
292 LiftedConnectionPoint proper) throws DatabaseException {
293 Layer0 L0 = Layer0.getInstance(graph);
294 DiagramResource DIA = DiagramResource.getInstance(graph);
295 ModelingResources MOD = ModelingResources.getInstance(graph);
296 StructuralResource2 STR = StructuralResource2.getInstance(graph);
298 Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);
299 if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation))
300 return "Wrong connection point (" + connectionPoint + ") attachment relation: is " + existingHasAttachment
301 + ", should be " + proper.attachmentRelation;
304 Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, L0.InstanceOf));
305 Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null
306 ? graph.getObjects(proper.connectionPoint, L0.InstanceOf)
307 : Collections.<Resource>emptySet());
308 if (!existingTypes.equals(properTypes))
309 return "Incorrect connection point relation (" + connectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";
312 Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);
313 if (diagramConnectionPoint != null) {
314 Set<Resource> existingTypes = new THashSet<Resource>(graph.getObjects(diagramConnectionPoint, L0.InstanceOf));
315 Set<Resource> properTypes = new THashSet<Resource>(proper.connectionPoint != null
316 ? graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType)
317 : Collections.<Resource>emptySet());
318 if (!existingTypes.equals(properTypes))
319 return "Incorrect diagram connection point relation (" + diagramConnectionPoint + ") types (existing " + existingTypes + " vs. proper " + properTypes + ")";
321 Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));
322 for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {
323 Set<Resource> existingTerminalTypes = new THashSet<Resource>(graph.getObjects(terminal, L0.InstanceOf));
324 if (!existingTerminalTypes.equals(properTerminalTypes))
325 return "Incorrect diagram connection point relation types (existing " + existingTypes + " vs. proper " + properTypes + ")";
334 * @param componentType
335 * @param connectionPoint
337 * @return <code>null</code> if connection point was properly validated
338 * @throws DatabaseException
340 public static String validateConnectionPoint(WriteGraph graph, Resource componentType, Resource connectionPoint,
341 LiftedConnectionPoint proper) throws DatabaseException {
343 Layer0 L0 = Layer0.getInstance(graph);
344 DiagramResource DIA = DiagramResource.getInstance(graph);
345 ModelingResources MOD = ModelingResources.getInstance(graph);
346 StructuralResource2 STR = StructuralResource2.getInstance(graph);
348 // Fix HasAttachmentRelation of connectionPoint
349 Resource existingHasAttachment = graph.getPossibleObject(connectionPoint, STR.HasAttachmentRelation);
350 if (!ObjectUtils.objectEquals(existingHasAttachment, proper.attachmentRelation)) {
351 graph.deny(connectionPoint, STR.HasAttachmentRelation);
352 if (proper.attachmentRelation != null)
353 graph.claim(connectionPoint, STR.HasAttachmentRelation, proper.attachmentRelation);
356 // Fix InstanceOf's of connectionPoint
357 fixDirectTypes(graph, connectionPoint, proper.connectionPoint != null
358 ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, L0.InstanceOf) )
359 : Collections.<Resource>emptySet());
361 // Fix InstanceOf's of connection point's diagram connection relation
362 Resource diagramConnectionPoint = graph.getPossibleObject(connectionPoint, MOD.ConnectionRelationToDiagramConnectionRelation);
363 if (diagramConnectionPoint != null) {
364 fixDirectTypes(graph, diagramConnectionPoint, proper.connectionPoint != null
365 ? new THashSet<Resource>( graph.getObjects(proper.connectionPoint, MOD.ImpliesDiagramConnectionRelationType) )
366 : Collections.<Resource>emptySet());
368 // Fix InstanceOf's of connection point's diagram connection relation's symbol terminal
369 Set<Resource> properTerminalTypes = new THashSet<Resource>(graph.getObjects(connectionPoint, MOD.ConnectionRelationToTerminal));
370 for (Resource terminal : graph.getObjects(diagramConnectionPoint, DIA.HasConnectionPoint_Inverse)) {
371 fixDirectTypes(graph, terminal, properTerminalTypes);
382 * @throws DatabaseException
384 private static void fixDirectTypes(WriteGraph graph, Resource r, Set<Resource> properTypes) throws DatabaseException {
385 Layer0 L0 = Layer0.getInstance(graph);
386 Set<Resource> existingTypes = new THashSet<Resource>( graph.getObjects(r, L0.InstanceOf) );
387 if (!existingTypes.equals(properTypes)) {
388 Set<Resource> addTypes = new THashSet<Resource>(properTypes);
389 properTypes.removeAll(existingTypes);
390 existingTypes.removeAll(properTypes);
391 for (Resource remove : existingTypes)
392 graph.deny(r, L0.InstanceOf, remove);
393 for (Resource add : addTypes)
394 graph.claim(r, L0.InstanceOf, null, add);