/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.diagram.flag; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.PossibleObjectWithType; import org.simantics.db.common.request.TernaryRead; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ServiceException; import org.simantics.db.function.DbConsumer; import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.db.layer0.variable.Variable; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.flag.IFlagType.FlagInfo; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; import org.simantics.g2d.elementclass.FlagClass; import org.simantics.layer0.Layer0; import org.simantics.layer0.utils.triggers.IActivationManager; import org.simantics.modeling.ModelingResources; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.structural2.modelingRules.IModelingRules; import org.simantics.structural2.queries.Terminal; import org.simantics.structural2.variables.ConnectionBrowser; import org.simantics.structural2.variables.ResourceWithContext; import org.simantics.utils.datastructures.Triple; import gnu.trove.set.hash.THashSet; /** * @author Tuukka Lehtonen */ public final class FlagUtil { public static boolean isDisconnected(ReadGraph graph, Resource flag) throws DatabaseException { return !isJoined(graph, flag) && !isMarkedExternal(graph, flag); } private static boolean isMarkedExternal(ReadGraph graph, Resource flag) throws DatabaseException { return graph.hasStatement(flag, DiagramResource.getInstance(graph).ExternalFlag); } public static boolean isExternal(ReadGraph graph, Resource flag) throws DatabaseException { return isMarkedExternal(graph, flag) && !isJoined(graph, flag); } public static boolean isJoined(ReadGraph graph, Resource flag) throws DatabaseException { return countCounterparts(graph, flag) > 0; } public static boolean isLifted(ReadGraph graph, Resource flag) throws DatabaseException { Resource cp = getPossibleConnectionPoint(graph, flag); return cp == null ? false : graph.isInstanceOf(cp, StructuralResource2.getInstance(graph).ConnectionRelation); } public static Resource getPossibleConnectionPoint(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); return graph.getPossibleObject(flag, DIA.IsLiftedAs); } public static Resource getPossibleCounterpart(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { if (flag.equals(otherFlag)) continue; return otherFlag; } } return null; } public static int countCounterparts(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); int result = 0; for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { if (flag.equals(otherFlag)) continue; ++result; } } return result; } public static Set getCounterparts(ReadGraph graph, Resource flag, Set result) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { if (flag.equals(otherFlag)) continue; result.add(otherFlag); } } return result; } public static int forCounterparts(ReadGraph graph, Resource flag, DbConsumer procedure) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); int count = 0; for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { if (!flag.equals(otherFlag)) { procedure.accept(otherFlag); ++count; } } } return count; } /** * Returns all flags that are joined with the given flag including the flag given as parameter. */ public static Set getCounterparts(ReadGraph graph, Resource flag) throws DatabaseException { return getCounterparts(graph, flag, new HashSet(8)); } public static Set getCounterpartsAndSelf(ReadGraph graph, Resource flag, Set result) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { result.add(otherFlag); } } if (result.size() == 0) result.add(flag); return result; } public static Set getCounterpartsAndSelf(ReadGraph graph, Resource flag) throws DatabaseException { return getCounterpartsAndSelf(graph, flag, new HashSet(8)); } /** * @param g * @param flag * @param otherFlag * @return the created DIA.ConnectionJoin instance * @throws DatabaseException */ public static Resource join(WriteGraph g, Resource flag, Resource otherFlag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); Resource connectionJoin = g.newResource(); Layer0 L0 = Layer0.getInstance(g); g.claim(connectionJoin, L0.InstanceOf, null, STR.ConnectionJoin); g.claim(connectionJoin, DIA.JoinsFlag, flag); g.claim(connectionJoin, DIA.JoinsFlag, otherFlag); IActivationManager manager = g.getService(IActivationManager.class); for(Resource diagram : OrderedSetUtils.getSubjects(g, flag)) manager.activateOnce(diagram); for(Resource diagram : OrderedSetUtils.getSubjects(g, otherFlag)) manager.activateOnce(diagram); return connectionJoin; } public static void disconnectFlag(WriteGraph graph, Resource flag) throws DatabaseException { // Remove any :ConnectionJoin's this flag is joined by // if there's less than two flags joined by the join. DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); THashSet affectedConnections = new THashSet(4); for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins)); graph.deny(flag, DIA.FlagIsJoinedBy, connectionJoin); if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) { RemoverUtil.remove(graph, connectionJoin); } } fixBindsStatements(graph, STR, DIA, affectedConnections); } private static boolean isBindsStatementLegimite(ReadGraph graph, DiagramResource DIA, Resource connection, Resource connectionRelation) throws DatabaseException { ModelingResources MOD = ModelingResources.getInstance(graph); for(Resource diagramConnection : graph.getObjects(connection, MOD.ConnectionToDiagramConnection)) for(Resource connector : graph.getObjects(diagramConnection, DIA.HasConnector)) for(Resource flag : graph.getObjects(connector, DIA.Flag_ConnectionPoint_Inverse)) if(graph.hasStatement(flag, DIA.IsLiftedAs, connectionRelation)) return true; return false; } private static void fixBindsStatements(WriteGraph graph, StructuralResource2 STR, DiagramResource DIA, Collection connections) throws DatabaseException { for(Resource connection : connections) for(Resource connectionRelation : graph.getObjects(connection, STR.Binds)) if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation)) graph.denyStatement(connection, STR.Binds, connectionRelation); } public static void fixBindsStatements(WriteGraph graph, Resource connection) throws DatabaseException { if(connection == null) return; DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); for(Resource connectionRelation : graph.getObjects(connection, STR.Binds)) if(!isBindsStatementLegimite(graph, DIA, connection, connectionRelation)) graph.denyStatement(connection, STR.Binds, connectionRelation); } public static void disconnectFlag(WriteGraph graph, Resource flag, Resource fromFlag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); THashSet affectedConnections = new THashSet(4); for (Resource connectionJoin : graph.getObjects(flag, DIA.FlagIsJoinedBy)) { affectedConnections.addAll(graph.getObjects(connectionJoin, STR.Joins)); for (Resource otherFlag : graph.getObjects(connectionJoin, DIA.JoinsFlag)) { if (flag.equals(otherFlag)) continue; if (otherFlag.equals(fromFlag)) { graph.deny(connectionJoin, DIA.JoinsFlag, DIA.FlagIsJoinedBy, flag); if (graph.getObjects(connectionJoin, DIA.JoinsFlag).size() < 2) { RemoverUtil.remove(graph, connectionJoin); } } } } fixBindsStatements(graph, STR, DIA, affectedConnections); } public static void removeFlag(WriteGraph graph, Resource flag) throws DatabaseException { disconnectFlag(graph, flag); RemoverUtil.remove(graph, flag); } public static boolean isJoinedInSingleDiagram(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Resource counterpart = getPossibleCounterpart(graph, flag); if (counterpart == null) return false; return !Collections.disjoint( OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram), OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)); } public static boolean isJoinedBetweenDiagrams(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Collection counterparts = getCounterparts(graph, flag); if (counterparts.isEmpty()) return false; Collection flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram); for (Resource counterpart : counterparts) if (Collections.disjoint( flagDiagrams, OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram))) return true; return false; } /** * @return * @throws DatabaseException */ public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag) throws DatabaseException { return getFlagType(graph, flag, null); } /** * @return * @throws DatabaseException */ public static FlagClass.Type getFlagType(ReadGraph graph, Resource flag, FlagClass.Type defaultFlagType) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Resource type = graph.getPossibleObject(flag, DIA.HasFlagType); return DiagramGraphUtil.toFlagType(DIA, type, defaultFlagType); } /** * @return * @throws DatabaseException */ public static void setFlagType(WriteGraph graph, Resource flag, FlagClass.Type type) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); Resource flagType = DiagramGraphUtil.toFlagTypeResource(DIA, type); Resource existingFlagType = graph.getPossibleObject(flag, DIA.HasFlagType); if (flagType.equals(existingFlagType)) return; graph.deny(flag, DIA.HasFlagType); // Resource defaultFlagType = graph.getPossibleObject(flag, DIA.HasFlagType); // if (flagType.equals(defaultFlagType)) // return; graph.claim(flag, DIA.HasFlagType, null, flagType); } public static Set findDirectlyConnectedComponents(ReadGraph graph, Resource flag) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) { Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector); if (diagramConnection == null) continue; Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection); if (connection == null) continue; return new HashSet(graph.getObjects(connection, STR.Connects)); } return Collections.emptySet(); } public static Set findDirectlyConnectedTerminals(ReadGraph graph, Resource flag) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); for (Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) { Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector); if (diagramConnection == null) continue; Resource connection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection); if (connection == null) continue; Set terminals = new HashSet(); for (Statement stm : graph.getStatements(connection, STR.Connects)) { terminals.add(new Terminal(stm.getObject(), graph.getInverse(stm.getPredicate()))); } return terminals; } return Collections.emptySet(); } /** * @param graph * @param flag * @return set of (module, terminal relation, attachment relation) triples * @throws DatabaseException */ public static Set> findDirectlyConnectedElementTerminals(ReadGraph graph, Resource toElement) throws DatabaseException { StructuralResource2 STR = StructuralResource2.getInstance(graph); DiagramResource DIA = DiagramResource.getInstance(graph); Set> result = new HashSet>(); for (Resource connector : graph.getObjects(toElement, STR.IsConnectedTo)) { Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, connector); if (diagramConnection == null) continue; //System.out.println("DC: " + NameUtils.getSafeName(graph, diagramConnection, true)); for (Statement connectionToConnector : graph.getStatements(diagramConnection, DIA.HasConnector)) { Resource connector2 = connectionToConnector.getObject(); if (connector.equals(connector2)) continue; Resource attachmentRelation = connectionToConnector.getPredicate(); // Get element + terminal relation for (Statement connectorToElement : graph.getStatements(connector2, STR.Connects)) { Resource element = connectorToElement.getObject(); if (diagramConnection.equals(element)) continue; Resource terminalRelation = graph.getPossibleInverse(connectorToElement.getPredicate()); if (terminalRelation == null) continue; result.add(Triple.make(element, terminalRelation, attachmentRelation)); } } } return result; } public static Variable getPossibleFlagSignal(ReadGraph graph, Variable configuration, Resource flag, Resource type) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); ModelingResources MOD = ModelingResources.getInstance(graph); Resource component = graph.getPossibleObject(flag, MOD.ElementToComponent); if (component != null && graph.isInstanceOf(component, type)) { Variable v = configuration.browsePossible(graph, component); if (v != null) return v; } Resource connector = graph.getPossibleObject(flag, DIA.Flag_ConnectionPoint); if(connector == null) return null; Resource connection = graph.sync(new PossibleObjectWithType(connector, DIA.IsConnectorOf, DIA.Connection)); if(connection == null) return null; return getPossibleConnectionSignal(graph, configuration, connection, type); } public static Variable getPossibleConnectionSignal(ReadGraph graph, Variable configuration, Resource connection, Resource type) throws DatabaseException { return graph.syncRequest(new PossibleConnectionSignal(configuration, connection, type), TransientCacheListener.instance()); } public static class PossibleConnectionSignal extends TernaryRead { public PossibleConnectionSignal(Variable configuration, Resource connection, Resource type) { super(configuration, connection, type); } @Override public Variable perform(ReadGraph graph) throws DatabaseException { ModelingResources MOD = ModelingResources.getInstance(graph); DiagramResource DIA = DiagramResource.getInstance(graph); Resource connection = parameter2; Resource mapped = graph.getPossibleObject(connection, MOD.DiagramConnectionToConnection); if(mapped != null) connection = mapped; for (ResourceWithContext module : ConnectionBrowser.findConnectedComponents(graph, connection, parameter)) { if (graph.isInstanceOf(module.getResource(), parameter3)) { Resource element = graph.getPossibleObject(module.getResource(), MOD.ComponentToElement); if(element != null) { if(graph.isInstanceOf(element, DIA.Flag) || graph.isInstanceOf(element, DIA.Connection)) return module.getContext(); } else { System.err.println("no element for " + NameUtils.getSafeName(graph, module.getResource())); } } } return null; } } /** * Verifies that the specified flag has the correct flag type as resolved * through {@link IFlagType}. Please note that using this method assumes * that the diagram mapping has been executed and the configuration is in * sync with the diagram. * * @param graph * @param modelingRules * modeling rules for getting the connection type of the flag for * retrieving {@link IFlagTypeReader} and {@link IFlagType} * @param flag * the flag for to verify type * @param flagType * the current type of the flag * @throws DatabaseException */ public static void verifyFlagType(WriteGraph graph, IModelingRules modelingRules, Resource flag, FlagClass.Type flagType) throws DatabaseException { if (modelingRules != null) { // Follows the flag loading logic in FlagClassFactory. IFlagTypeReader ftr = null; Resource connectionType = DiagramGraphUtil.getConnectionTypeForFlag(graph, flag); if (connectionType != null) { //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", CONNECTION TYPE " + NameUtils.getSafeName(g, connectionType)); ftr = graph.getPossibleAdapter(connectionType, IFlagTypeReader.class); } if (ftr == null) { //System.out.println("FLAG " + NameUtils.getSafeName(g, flag) + ", NO CONNECTION TYPE"); ftr = graph.getPossibleAdapter(flag, IFlagTypeReader.class); } if (ftr != null) { IFlagType ft = ftr.read(graph, flag, modelingRules); if (ft != null) { FlagInfo info = ft.getInfo(graph); if (flagType != info.getType()) { FlagUtil.setFlagType(graph, flag, info.getType()); } } } } } public static List setFlagExternal (WriteGraph graph, List flags, boolean external) throws ServiceException { DiagramResource DIA = DiagramResource.getInstance(graph); for (Resource flag : flags) { if (external) graph.claim(flag, DIA.ExternalFlag, DIA.ExternalFlag, flag); else graph.deny(flag, DIA.ExternalFlag); } return flags; } }