X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.structural2%2Fsrc%2Forg%2Fsimantics%2Fstructural2%2FmodelingRules%2FStandardModelingRules.java;fp=bundles%2Forg.simantics.structural2%2Fsrc%2Forg%2Fsimantics%2Fstructural2%2FmodelingRules%2FStandardModelingRules.java;h=a45edf0eef1c1e2f2fa2a28ec1a5449f76c71530;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java b/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java new file mode 100644 index 000000000..a45edf0ee --- /dev/null +++ b/bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * 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.structural2.modelingRules; + + +import gnu.trove.set.hash.THashSet; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Statement; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.layer0.Layer0; +import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.structural2.utils.StructuralUtils; +import org.simantics.utils.strings.AlphanumComparator; + +public class StandardModelingRules extends AbstractModelingRules { + + Layer0 L0; + StructuralResource2 STR; + + public StandardModelingRules(ReadGraph g) { + L0 = Layer0.getInstance(g); + STR = StructuralResource2.getInstance(g); + } + + private ConnectionJudgement judgeConnection(ReadGraph g, + Collection connectionPoints, boolean allowExisting) + throws DatabaseException { + + // TODO: not a 100% sure if this is safe, will some critical cases break + // in other applications than Apros? Anyway, this by default allows + // any connections without classifiable connection points. + if (connectionPoints.isEmpty()) { + ConnectionJudgement judgement = new ConnectionJudgement(ConnectionJudgementType.LEGAL); + judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE; + return judgement; + } + + // Check that connecting to all of the terminals is allowed + if(!allowExisting) { + for(IConnectionPoint cp : connectionPoints) { + if(cp instanceof CPTerminal) { + CPTerminal terminal = (CPTerminal)cp; + if(g.isInstanceOf(terminal.relation, L0.FunctionalRelation)) { + if(terminal.component == null) + continue; + if (g.hasStatement(terminal.component, terminal.relation)) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(terminal.toString(g) + " failed FunctionalRelation test -> ILLEGAL"); + return ConnectionJudgement.ILLEGAL; + } + for(Resource eqRelation : g.getObjects(terminal.relation, STR.ConnectionRelation_equivalentConnectionPoint)) + if (g.hasStatement(terminal.component, eqRelation)) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(terminal.toString(g) + " failed FunctionalRelation test of equivalent connection point -> ILLEGAL"); + return ConnectionJudgement.ILLEGAL; + } + } + } + } + } + + // Translate all connection points to terminals + Set terminals = resolveTerminals(g, connectionPoints); + + // If there is a single default connection type that all connection + // points agree on, it will be stored here. It will be used if there + // is no single unambiguous connection type + Resource defaultConnectionType = null; + boolean singleDefaultConnectionType = false; + + // Determine the set of connection types all connection points accept + Collection> typeSets = new ArrayList>(); + for(CPTerminal terminal : terminals) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(this + ": allowed connection types determination: " + terminal.toString(g) + " " + terminal.relation); + Collection allowedConnectionTypes = g.syncRequest(new AllowedConnectionTypes(terminal.relation)); + if(Policy.DEBUG_STANDARD_MODELING_RULES) + for (Resource type : allowedConnectionTypes) + System.out.println("\tallowedConnectionType: " + NameUtils.getSafeName(g, type, true)); + typeSets.add(new THashSet(allowedConnectionTypes)); + + // Default connection type calculation + Resource defaultsTo = g.getPossibleObject(terminal.relation, STR.DefaultsToConnectionType); + if (defaultsTo != null) { + if (defaultConnectionType == null) { + defaultConnectionType = defaultsTo; + singleDefaultConnectionType = true; + } else if (!defaultsTo.equals(defaultConnectionType)) { + singleDefaultConnectionType = false; + } + } + } + + Collection connectionTypes = getAllowedConnectionTypes(g, typeSets); + + if(connectionTypes == null) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println("No connection types -> CANBEMADELEGAL"); + return ConnectionJudgement.CANBEMADELEGAL; + } + + // Validate connection types + Resource possibleConnectionType = null; + Resource chosenConnectionType = null; + String chosenConnectionTypeName = null; + connectionTypeLoop: + for(Resource connectionType : connectionTypes) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println("Check constraints for " + NameUtils.getSafeName(g, connectionType)); + + switch (evaluateConstraints(g, connectionType, terminals)) { + case ILLEGAL: + continue connectionTypeLoop; + + case CANBEMADELEGAL: + possibleConnectionType = connectionType; + break; + + case LEGAL: + if (chosenConnectionType != null) { + if (singleDefaultConnectionType) { + chosenConnectionType = defaultConnectionType; + break connectionTypeLoop; + } + // There is no single unambiguous legal connection type. + // Make a deterministic choice out of the available types + // based on their names. Select that connection type placed + // first in ascending lexicograpical order. + if (chosenConnectionTypeName == null) + chosenConnectionTypeName = NameUtils.getSafeName(g, chosenConnectionType); + String connectionTypeName = NameUtils.getSafeName(g, connectionType); + if (AlphanumComparator.COMPARATOR.compare(chosenConnectionTypeName, connectionTypeName) > 0) { + chosenConnectionType = connectionType; + chosenConnectionTypeName = connectionTypeName; + } + } else { + chosenConnectionType = connectionType; + } + } + } + + // Create result + if(chosenConnectionType != null) { + ConnectionJudgement judgement = new ConnectionJudgement(chosenConnectionType); + judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE; + return judgement; + } + else if(possibleConnectionType != null) { + ConnectionJudgement judgement = new ConnectionJudgement( + ConnectionJudgementType.CANBEMADELEGAL, possibleConnectionType); + judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE; + return judgement; + } + else + return ConnectionJudgement.ILLEGAL; + } + + private Collection getAllowedConnectionTypes(ReadGraph graph, Collection> typeSets) throws DatabaseException { + + // Preprocess sets according to STR.IsIncludedInConnectionType + Set all = new THashSet(); + for(Set s : typeSets) all.addAll(s); + for(Resource r : all) + for(Resource inc : graph.getObjects(r, STR.IsIncludedInConnectionType)) + for(Set s : typeSets) + if(s.contains(inc)) s.add(r); + + ArrayList connectionTypes = null; + for(Set allowedConnectionTypes : typeSets) { + if(!allowedConnectionTypes.isEmpty()) { + if(connectionTypes == null) + connectionTypes = new ArrayList(allowedConnectionTypes); + else + connectionTypes.retainAll(allowedConnectionTypes); + } + } + + return connectionTypes; + + } + + private ConnectionJudgementType evaluateConstraints(ReadGraph g, Resource connectionType, Set terminals) throws DatabaseException { + boolean legal = true; + for (Resource constraint : g.getObjects(connectionType, STR.HasConnectionConstraint)) { + IConnectionConstraint cc = g.adapt(constraint, IConnectionConstraint.class); + switch(cc.isLegal(g, terminals)) { + case ILLEGAL: + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(" " + cc.getClass().getSimpleName() + + " -> ILLEGAL"); + return ConnectionJudgementType.ILLEGAL; + case CANBEMADELEGAL: + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(" " + cc.getClass().getSimpleName() + + " -> CANBEMADELEGAL"); + legal = false; + default: + break; + } + } + return legal ? ConnectionJudgementType.LEGAL : ConnectionJudgementType.CANBEMADELEGAL; + } + + @Override + public ConnectionJudgement judgeConnection(ReadGraph g, + Collection connectionPoints) + throws DatabaseException { + + return judgeConnection(g, connectionPoints, false); + + } + + @Override + public Resource computeConnectionType(ReadGraph g, + Collection connectionPoints) + throws DatabaseException { + + return judgeConnection(g, connectionPoints, true).connectionType; + + } + + @Override + public IAttachmentRelationMap getAttachmentRelations(ReadGraph g, + Resource connection) { + return StandardAttachmentRelationMap.INSTANCE; + } + + @Override + public Set resolveTerminals(ReadGraph g, Collection connectionPoints) + throws DatabaseException { + Set terminals = new THashSet(); + StructuralResource2 STR = StructuralResource2.getInstance(g); + for(IConnectionPoint cp : connectionPoints) { + if(Policy.DEBUG_STANDARD_MODELING_RULES) + System.out.println(this + ": translate connection point: " + cp.toString(g)); + if(cp instanceof CPTerminal) + terminals.add((CPTerminal)cp); + else if(cp instanceof CPConnection) { + CPConnection connection = (CPConnection)cp; + for (Resource c : StructuralUtils.getRelatedConnections(g, connection.connection)) { + for (Statement stat : g.getStatements(c, STR.Connects)) + terminals.add(new CPTerminal(stat.getObject(), + g.getInverse(stat.getPredicate()))); + Resource inf = g.getPossibleObject(c, STR.Binds); + // TODO: figure out a better component + if(inf != null) terminals.add(new CPTerminal(inf, inf)); + } + } + else if(cp instanceof CPConnectionJoin) { + CPConnectionJoin connectionJoin = (CPConnectionJoin)cp; + for (Resource c : StructuralUtils.getRelatedConnectionsOfConnectionJoin(g, connectionJoin.connectionJoin)) + for (Statement stat : g.getStatements(c, STR.Connects)) + terminals.add(new CPTerminal(stat.getObject(), + g.getInverse(stat.getPredicate()))); + } + else + throw new IllegalArgumentException("Connection point " + cp + " encountered."); + } + + return terminals; + + } + +}