1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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.diagram.flag;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.HashSet;
17 import java.util.List;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Resource;
22 import org.simantics.db.Statement;
23 import org.simantics.db.WriteGraph;
24 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
25 import org.simantics.db.common.request.PossibleObjectWithType;
26 import org.simantics.db.common.request.TernaryRead;
27 import org.simantics.db.common.utils.NameUtils;
28 import org.simantics.db.common.utils.OrderedSetUtils;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.exception.ServiceException;
31 import org.simantics.db.function.DbBiFunction;
32 import org.simantics.db.function.DbConsumer;
33 import org.simantics.db.layer0.util.RemoverUtil;
34 import org.simantics.db.layer0.variable.Variable;
35 import org.simantics.diagram.content.ConnectionUtil;
36 import org.simantics.diagram.flag.IFlagType.FlagInfo;
37 import org.simantics.diagram.stubs.DiagramResource;
38 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;
39 import org.simantics.g2d.elementclass.FlagClass;
40 import org.simantics.layer0.Layer0;
41 import org.simantics.layer0.utils.triggers.IActivationManager;
42 import org.simantics.modeling.ModelingResources;
43 import org.simantics.structural.stubs.StructuralResource2;
44 import org.simantics.structural2.modelingRules.IModelingRules;
45 import org.simantics.structural2.queries.Terminal;
46 import org.simantics.structural2.variables.ConnectionBrowser;
47 import org.simantics.structural2.variables.ResourceWithContext;
48 import org.simantics.utils.datastructures.Triple;
50 import gnu.trove.set.hash.THashSet;
53 * @author Tuukka Lehtonen
55 public final class FlagUtil {
57 public static boolean isDisconnected(ReadGraph graph, Resource flag) throws DatabaseException {
58 return !isJoined(graph, flag) && !isMarkedExternal(graph, flag);
61 private static boolean isMarkedExternal(ReadGraph graph, Resource flag) throws DatabaseException {
62 return graph.hasStatement(flag, DiagramResource.getInstance(graph).ExternalFlag);
65 public static boolean isExternal(ReadGraph graph, Resource flag) throws DatabaseException {
66 return isMarkedExternal(graph, flag) && !isJoined(graph, flag);
69 public static boolean isJoined(ReadGraph graph, Resource flag) throws DatabaseException {
70 return countCounterparts(graph, flag) > 0;
73 public static boolean isLifted(ReadGraph graph, Resource flag) throws DatabaseException {
74 Resource cp = getPossibleConnectionPoint(graph, flag);
75 return cp == null ? false : graph.isInstanceOf(cp, StructuralResource2.getInstance(graph).ConnectionRelation);
78 public static Resource getPossibleConnectionPoint(ReadGraph graph, Resource flag) throws DatabaseException {
79 DiagramResource DIA = DiagramResource.getInstance(graph);
80 return graph.getPossibleObject(flag, DIA.IsLiftedAs);
83 public static Resource getPossibleCounterpart(ReadGraph graph, Resource flag) throws DatabaseException {
84 DiagramResource DIA = DiagramResource.getInstance(graph);
85 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
86 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
87 if (flag.equals(otherFlag))
95 public static int countCounterparts(ReadGraph graph, Resource flag) throws DatabaseException {
96 DiagramResource DIA = DiagramResource.getInstance(graph);
98 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
99 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
100 if (flag.equals(otherFlag))
108 public static Set<Resource> getCounterparts(ReadGraph graph, Resource flag, Set<Resource> result) throws DatabaseException {
109 DiagramResource DIA = DiagramResource.getInstance(graph);
110 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
111 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
112 if (flag.equals(otherFlag))
114 result.add(otherFlag);
120 public static int forCounterparts(ReadGraph graph, Resource flag, DbConsumer<Resource> procedure) throws DatabaseException {
121 DiagramResource DIA = DiagramResource.getInstance(graph);
123 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
124 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
125 if (!flag.equals(otherFlag)) {
126 procedure.accept(otherFlag);
134 public static int forCounterparts(ReadGraph graph, Resource flag, DbBiFunction<Resource, Resource, Boolean> procedure) throws DatabaseException {
135 DiagramResource DIA = DiagramResource.getInstance(graph);
137 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
138 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
139 if (!flag.equals(otherFlag)) {
140 if (!procedure.apply(connectionJoin, otherFlag))
150 * Returns all flags that are joined with the given flag including the flag given as parameter.
152 public static Set<Resource> getCounterparts(ReadGraph graph, Resource flag) throws DatabaseException {
153 return getCounterparts(graph, flag, new HashSet<Resource>(8));
156 public static Set<Resource> getCounterpartsAndSelf(ReadGraph graph, Resource flag, Set<Resource> result) throws DatabaseException {
157 DiagramResource DIA = DiagramResource.getInstance(graph);
158 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
159 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
160 result.add(otherFlag);
163 if (result.size() == 0)
168 public static Set<Resource> getCounterpartsAndSelf(ReadGraph graph, Resource flag) throws DatabaseException {
169 return getCounterpartsAndSelf(graph, flag, new HashSet<Resource>(8));
175 * @return the created DIA.ConnectionJoin instance
176 * @throws DatabaseException
178 public static Resource join(WriteGraph g, Resource flag, Resource otherFlag) throws DatabaseException {
179 DiagramResource DIA = DiagramResource.getInstance(g);
180 StructuralResource2 STR = StructuralResource2.getInstance(g);
181 Resource connectionJoin = g.newResource();
182 Layer0 L0 = Layer0.getInstance(g);
183 g.claim(connectionJoin, L0.InstanceOf, null, STR.ConnectionJoin);
184 g.claim(connectionJoin, DIA.JoinsFlag, flag);
185 g.claim(connectionJoin, DIA.JoinsFlag, otherFlag);
187 IActivationManager manager = g.getService(IActivationManager.class);
188 for(Resource diagram : OrderedSetUtils.getSubjects(g, flag))
189 manager.activateOnce(g, diagram);
190 for(Resource diagram : OrderedSetUtils.getSubjects(g, otherFlag))
191 manager.activateOnce(g, diagram);
192 return connectionJoin;
195 public static void disconnectFlag(WriteGraph graph, Resource flag) throws DatabaseException {
196 // Remove any :ConnectionJoin's this flag is joined by
197 // if there's less than two flags joined by the join.
198 DiagramResource DIA = DiagramResource.getInstance(graph);
199 StructuralResource2 STR = StructuralResource2.getInstance(graph);
200 THashSet<Resource> affectedConnections = new THashSet<Resource>(4);
201 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
202 affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins));
203 graph.deny(flag, DIA.FlagIsJoinedBy, connectionJoin);
204 if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) {
205 RemoverUtil.remove(graph, connectionJoin);
208 fixBindsStatements(graph, STR, DIA, affectedConnections);
211 private static boolean isBindsStatementLegimite(ReadGraph graph,
214 Resource connectionRelation) throws DatabaseException {
215 ModelingResources MOD = ModelingResources.getInstance(graph);
216 for(Resource diagramConnection : graph.getObjects(connection, MOD.ConnectionToDiagramConnection))
217 for(Resource connector : graph.getObjects(diagramConnection, DIA.HasConnector))
218 for(Resource flag : graph.getObjects(connector, DIA.Flag_ConnectionPoint_Inverse))
219 if(graph.hasStatement(flag, DIA.IsLiftedAs, connectionRelation))
224 private static void fixBindsStatements(WriteGraph graph, StructuralResource2 STR, DiagramResource DIA, Collection<Resource> connections) throws DatabaseException {
225 for(Resource connection : connections)
226 for(Resource connectionRelation : graph.getObjects(connection, STR.Binds))
227 if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation))
228 graph.denyStatement(connection, STR.Binds, connectionRelation);
231 public static void fixBindsStatements(WriteGraph graph, Resource connection) throws DatabaseException {
232 if(connection == null)
234 DiagramResource DIA = DiagramResource.getInstance(graph);
235 StructuralResource2 STR = StructuralResource2.getInstance(graph);
236 for(Resource connectionRelation : graph.getObjects(connection, STR.Binds))
237 if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation))
238 graph.denyStatement(connection, STR.Binds, connectionRelation);
241 public static void disconnectFlag(WriteGraph graph, Resource flag, Resource fromFlag) throws DatabaseException {
242 DiagramResource DIA = DiagramResource.getInstance(graph);
243 StructuralResource2 STR = StructuralResource2.getInstance(graph);
244 THashSet<Resource> affectedConnections = new THashSet<Resource>(4);
245 for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) {
246 affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins));
247 for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) {
248 if (flag.equals(otherFlag))
250 if (otherFlag.equals(fromFlag)) {
251 graph.deny(connectionJoin, DIA.JoinsFlag, DIA.FlagIsJoinedBy, flag);
252 if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) {
253 RemoverUtil.remove(graph, connectionJoin);
258 fixBindsStatements(graph, STR, DIA, affectedConnections);
261 public static void removeFlag(WriteGraph graph, Resource flag) throws DatabaseException {
262 disconnectFlag(graph, flag);
263 RemoverUtil.remove(graph, flag);
269 * @return <code>true</code> only if the specified flag is joined only
270 * within the single diagram it resides in
271 * @throws DatabaseException
273 public static boolean isJoinedInSingleDiagram(ReadGraph graph, Resource flag) throws DatabaseException {
274 Collection<Resource> counterparts = getCounterparts(graph, flag);
275 if (counterparts.isEmpty())
277 DiagramResource DIA = DiagramResource.getInstance(graph);
278 Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);
279 for (Resource counterpart : counterparts) {
280 if (Collections.disjoint(flagDiagrams,
281 OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)))
287 public static boolean isJoinedBetweenDiagrams(ReadGraph graph, Resource flag) throws DatabaseException {
288 DiagramResource DIA = DiagramResource.getInstance(graph);
289 Collection<Resource> counterparts = getCounterparts(graph, flag);
290 if (counterparts.isEmpty())
292 Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);
293 for (Resource counterpart : counterparts)
294 if (Collections.disjoint(
296 OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)))
303 * @throws DatabaseException
305 public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag) throws DatabaseException {
306 return getFlagType(graph, flag, null);
311 * @throws DatabaseException
313 public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag, FlagClass.Type defaultFlagType) throws DatabaseException {
314 DiagramResource DIA = DiagramResource.getInstance(graph);
315 Resource type = graph.getPossibleObject(flag, DIA.HasFlagType);
316 return DiagramGraphUtil.toFlagType(DIA, type, defaultFlagType);
321 * @throws DatabaseException
323 public static void setFlagType(WriteGraph graph, Resource flag, FlagClass.Type type) throws DatabaseException {
324 DiagramResource DIA = DiagramResource.getInstance(graph);
325 Resource flagType = DiagramGraphUtil.toFlagTypeResource(DIA, type);
326 Resource existingFlagType = graph.getPossibleObject(flag, DIA.HasFlagType);
327 if (flagType.equals(existingFlagType))
329 graph.deny(flag, DIA.HasFlagType);
330 // Resource defaultFlagType = graph.getPossibleObject(flag, DIA.HasFlagType);
331 // if (flagType.equals(defaultFlagType))
333 graph.claim(flag, DIA.HasFlagType, null, flagType);
336 public static Set<Resource> findDirectlyConnectedComponents(ReadGraph graph, Resource flag) throws DatabaseException {
337 StructuralResource2 STR = StructuralResource2.getInstance(graph);
338 ModelingResources MOD = ModelingResources.getInstance(graph);
340 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
341 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
342 if (diagramConnection == null)
345 Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
346 if (connection == null)
349 return new HashSet<Resource>(graph.getObjects(connection, STR.Connects));
351 return Collections.emptySet();
354 public static Set<Terminal> findDirectlyConnectedTerminals(ReadGraph graph, Resource flag) throws DatabaseException {
355 StructuralResource2 STR = StructuralResource2.getInstance(graph);
356 ModelingResources MOD = ModelingResources.getInstance(graph);
358 for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) {
359 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
360 if (diagramConnection == null)
363 Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
364 if (connection == null)
367 Set<Terminal> terminals = new HashSet<Terminal>();
368 for (Statement stm : graph.getStatements(connection, STR.Connects)) {
369 terminals.add(new Terminal(stm.getObject(), graph.getInverse(stm.getPredicate())));
373 return Collections.emptySet();
379 * @return set of (module, terminal relation, attachment relation) triples
380 * @throws DatabaseException
382 public static Set<Triple<Resource,Resource,Resource>> findDirectlyConnectedElementTerminals(ReadGraph graph, Resource toElement) throws DatabaseException {
383 StructuralResource2 STR = StructuralResource2.getInstance(graph);
384 DiagramResource DIA = DiagramResource.getInstance(graph);
386 Set<Triple<Resource, Resource, Resource>> result = new HashSet<Triple<Resource, Resource, Resource>>();
388 for (Resource connector : graph.getObjects(toElement, STR.IsConnectedTo)) {
389 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector);
390 if (diagramConnection == null)
393 //System.out.println("DC: " + NameUtils.getSafeName(graph, diagramConnection, true));
395 for (Statement connectionToConnector : graph.getStatements(diagramConnection, DIA.HasConnector)) {
396 Resource connector2 = connectionToConnector.getObject();
397 if (connector.equals(connector2))
400 Resource attachmentRelation = connectionToConnector.getPredicate();
402 // Get element + terminal relation
403 for (Statement connectorToElement : graph.getStatements(connector2, STR.Connects)) {
404 Resource element = connectorToElement.getObject();
405 if (diagramConnection.equals(element))
407 Resource terminalRelation = graph.getPossibleInverse(connectorToElement.getPredicate());
408 if (terminalRelation == null)
410 result.add(Triple.make(element, terminalRelation, attachmentRelation));
418 public static Variable getPossibleFlagSignal(ReadGraph graph, Variable configuration, Resource flag, Resource type) throws DatabaseException {
420 DiagramResource DIA = DiagramResource.getInstance(graph);
421 ModelingResources MOD = ModelingResources.getInstance(graph);
423 Resource component = graph.getPossibleObject(flag, MOD.ElementToComponent);
424 if (component != null && graph.isInstanceOf(component, type)) {
425 Variable v = configuration.browsePossible(graph, component);
430 Resource connector = graph.getPossibleObject(flag, DIA.Flag_ConnectionPoint);
431 if(connector == null) return null;
433 Resource connection = graph.sync(new PossibleObjectWithType(connector, DIA.IsConnectorOf, DIA.Connection));
434 if(connection == null) return null;
436 return getPossibleConnectionSignal(graph, configuration, connection, type);
440 public static Variable getPossibleConnectionSignal(ReadGraph graph, Variable configuration, Resource connection, Resource type) throws DatabaseException {
442 return graph.syncRequest(new PossibleConnectionSignal(configuration, connection, type), TransientCacheListener.<Variable>instance());
446 public static class PossibleConnectionSignal extends TernaryRead<Variable, Resource, Resource, Variable> {
448 public PossibleConnectionSignal(Variable configuration, Resource connection, Resource type) {
449 super(configuration, connection, type);
453 public Variable perform(ReadGraph graph) throws DatabaseException {
455 ModelingResources MOD = ModelingResources.getInstance(graph);
456 DiagramResource DIA = DiagramResource.getInstance(graph);
458 Resource connection = parameter2;
459 Resource mapped = graph.getPossibleObject(connection, MOD.DiagramConnectionToConnection);
460 if(mapped != null) connection = mapped;
462 for (ResourceWithContext module : ConnectionBrowser.findConnectedComponents(graph, connection, parameter)) {
463 if (graph.isInstanceOf(module.getResource(), parameter3)) {
464 Resource element = graph.getPossibleObject(module.getResource(), MOD.ComponentToElement);
465 if(element != null) {
466 if(graph.isInstanceOf(element, DIA.Flag) || graph.isInstanceOf(element, DIA.Connection))
467 return module.getContext();
469 System.err.println("no element for " + NameUtils.getSafeName(graph, module.getResource()));
481 * Verifies that the specified flag has the correct flag type as resolved
482 * through {@link IFlagType}. Please note that using this method assumes
483 * that the diagram mapping has been executed and the configuration is in
484 * sync with the diagram.
487 * @param modelingRules
488 * modeling rules for getting the connection type of the flag for
489 * retrieving {@link IFlagTypeReader} and {@link IFlagType}
491 * the flag for to verify type
493 * the current type of the flag
494 * @throws DatabaseException
496 public static void verifyFlagType(WriteGraph graph, IModelingRules modelingRules, Resource flag, FlagClass.Type flagType) throws DatabaseException {
497 if (modelingRules != null) {
498 // Follows the flag loading logic in FlagClassFactory.
499 IFlagTypeReader ftr = null;
500 Resource connectionType = DiagramGraphUtil.getConnectionTypeForFlag(graph, flag);
501 if (connectionType != null) {
502 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", CONNECTION TYPE " + NameUtils.getSafeName(g, connectionType));
503 ftr = graph.getPossibleAdapter(connectionType, IFlagTypeReader.class);
506 //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", NO CONNECTION TYPE");
507 ftr = graph.getPossibleAdapter(flag, IFlagTypeReader.class);
511 IFlagType ft = ftr.read(graph, flag, modelingRules);
513 FlagInfo info = ft.getInfo(graph);
514 if (flagType != info.getType()) {
515 FlagUtil.setFlagType(graph, flag, info.getType());
522 public static List<Resource> setFlagExternal (WriteGraph graph, List<Resource> flags, boolean external) throws ServiceException {
524 DiagramResource DIA = DiagramResource.getInstance(graph);
525 for (Resource flag : flags) {
527 graph.claim(flag, DIA.ExternalFlag, DIA.ExternalFlag, flag);
529 graph.deny(flag, DIA.ExternalFlag);