--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.structural2.modelingRules;\r
+\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.utils.StructuralUtils;\r
+import org.simantics.utils.strings.AlphanumComparator;\r
+\r
+public class StandardModelingRules extends AbstractModelingRules {\r
+\r
+ Layer0 L0;\r
+ StructuralResource2 STR;\r
+\r
+ public StandardModelingRules(ReadGraph g) {\r
+ L0 = Layer0.getInstance(g);\r
+ STR = StructuralResource2.getInstance(g);\r
+ }\r
+\r
+ private ConnectionJudgement judgeConnection(ReadGraph g,\r
+ Collection<IConnectionPoint> connectionPoints, boolean allowExisting)\r
+ throws DatabaseException {\r
+\r
+ // TODO: not a 100% sure if this is safe, will some critical cases break\r
+ // in other applications than Apros? Anyway, this by default allows\r
+ // any connections without classifiable connection points.\r
+ if (connectionPoints.isEmpty()) {\r
+ ConnectionJudgement judgement = new ConnectionJudgement(ConnectionJudgementType.LEGAL);\r
+ judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE;\r
+ return judgement;\r
+ }\r
+\r
+ // Check that connecting to all of the terminals is allowed\r
+ if(!allowExisting) {\r
+ for(IConnectionPoint cp : connectionPoints) {\r
+ if(cp instanceof CPTerminal) {\r
+ CPTerminal terminal = (CPTerminal)cp;\r
+ if(g.isInstanceOf(terminal.relation, L0.FunctionalRelation)) {\r
+ if(terminal.component == null)\r
+ continue;\r
+ if (g.hasStatement(terminal.component, terminal.relation)) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(terminal.toString(g) + " failed FunctionalRelation test -> ILLEGAL");\r
+ return ConnectionJudgement.ILLEGAL;\r
+ }\r
+ for(Resource eqRelation : g.getObjects(terminal.relation, STR.ConnectionRelation_equivalentConnectionPoint))\r
+ if (g.hasStatement(terminal.component, eqRelation)) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(terminal.toString(g) + " failed FunctionalRelation test of equivalent connection point -> ILLEGAL");\r
+ return ConnectionJudgement.ILLEGAL;\r
+ } \r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Translate all connection points to terminals\r
+ Set<CPTerminal> terminals = resolveTerminals(g, connectionPoints);\r
+ \r
+ // If there is a single default connection type that all connection\r
+ // points agree on, it will be stored here. It will be used if there\r
+ // is no single unambiguous connection type \r
+ Resource defaultConnectionType = null;\r
+ boolean singleDefaultConnectionType = false;\r
+\r
+ // Determine the set of connection types all connection points accept\r
+ Collection<Set<Resource>> typeSets = new ArrayList<Set<Resource>>();\r
+ for(CPTerminal terminal : terminals) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(this + ": allowed connection types determination: " + terminal.toString(g) + " " + terminal.relation);\r
+ Collection<Resource> allowedConnectionTypes = g.syncRequest(new AllowedConnectionTypes(terminal.relation));\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ for (Resource type : allowedConnectionTypes)\r
+ System.out.println("\tallowedConnectionType: " + NameUtils.getSafeName(g, type, true));\r
+ typeSets.add(new THashSet<Resource>(allowedConnectionTypes));\r
+\r
+ // Default connection type calculation\r
+ Resource defaultsTo = g.getPossibleObject(terminal.relation, STR.DefaultsToConnectionType);\r
+ if (defaultsTo != null) {\r
+ if (defaultConnectionType == null) {\r
+ defaultConnectionType = defaultsTo;\r
+ singleDefaultConnectionType = true;\r
+ } else if (!defaultsTo.equals(defaultConnectionType)) {\r
+ singleDefaultConnectionType = false;\r
+ }\r
+ }\r
+ }\r
+ \r
+ Collection<Resource> connectionTypes = getAllowedConnectionTypes(g, typeSets);\r
+ \r
+ if(connectionTypes == null) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println("No connection types -> CANBEMADELEGAL");\r
+ return ConnectionJudgement.CANBEMADELEGAL;\r
+ }\r
+\r
+ // Validate connection types\r
+ Resource possibleConnectionType = null;\r
+ Resource chosenConnectionType = null;\r
+ String chosenConnectionTypeName = null;\r
+ connectionTypeLoop:\r
+ for(Resource connectionType : connectionTypes) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println("Check constraints for " + NameUtils.getSafeName(g, connectionType));\r
+\r
+ switch (evaluateConstraints(g, connectionType, terminals)) {\r
+ case ILLEGAL:\r
+ continue connectionTypeLoop;\r
+\r
+ case CANBEMADELEGAL:\r
+ possibleConnectionType = connectionType;\r
+ break;\r
+\r
+ case LEGAL:\r
+ if (chosenConnectionType != null) {\r
+ if (singleDefaultConnectionType) {\r
+ chosenConnectionType = defaultConnectionType;\r
+ break connectionTypeLoop;\r
+ }\r
+ // There is no single unambiguous legal connection type.\r
+ // Make a deterministic choice out of the available types\r
+ // based on their names. Select that connection type placed\r
+ // first in ascending lexicograpical order. \r
+ if (chosenConnectionTypeName == null)\r
+ chosenConnectionTypeName = NameUtils.getSafeName(g, chosenConnectionType);\r
+ String connectionTypeName = NameUtils.getSafeName(g, connectionType);\r
+ if (AlphanumComparator.COMPARATOR.compare(chosenConnectionTypeName, connectionTypeName) > 0) {\r
+ chosenConnectionType = connectionType;\r
+ chosenConnectionTypeName = connectionTypeName;\r
+ }\r
+ } else {\r
+ chosenConnectionType = connectionType;\r
+ }\r
+ }\r
+ }\r
+ \r
+ // Create result\r
+ if(chosenConnectionType != null) {\r
+ ConnectionJudgement judgement = new ConnectionJudgement(chosenConnectionType);\r
+ judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE;\r
+ return judgement;\r
+ }\r
+ else if(possibleConnectionType != null) {\r
+ ConnectionJudgement judgement = new ConnectionJudgement(\r
+ ConnectionJudgementType.CANBEMADELEGAL, possibleConnectionType);\r
+ judgement.attachmentRelations = StandardAttachmentRelationMap.INSTANCE;\r
+ return judgement;\r
+ }\r
+ else\r
+ return ConnectionJudgement.ILLEGAL;\r
+ }\r
+\r
+ private Collection<Resource> getAllowedConnectionTypes(ReadGraph graph, Collection<Set<Resource>> typeSets) throws DatabaseException {\r
+ \r
+ // Preprocess sets according to STR.IsIncludedInConnectionType\r
+ Set<Resource> all = new THashSet<Resource>();\r
+ for(Set<Resource> s : typeSets) all.addAll(s);\r
+ for(Resource r : all)\r
+ for(Resource inc : graph.getObjects(r, STR.IsIncludedInConnectionType))\r
+ for(Set<Resource> s : typeSets)\r
+ if(s.contains(inc)) s.add(r);\r
+ \r
+ ArrayList<Resource> connectionTypes = null;\r
+ for(Set<Resource> allowedConnectionTypes : typeSets) {\r
+ if(!allowedConnectionTypes.isEmpty()) {\r
+ if(connectionTypes == null)\r
+ connectionTypes = new ArrayList<Resource>(allowedConnectionTypes);\r
+ else\r
+ connectionTypes.retainAll(allowedConnectionTypes);\r
+ }\r
+ }\r
+\r
+ return connectionTypes;\r
+ \r
+ }\r
+\r
+ private ConnectionJudgementType evaluateConstraints(ReadGraph g, Resource connectionType, Set<CPTerminal> terminals) throws DatabaseException {\r
+ boolean legal = true;\r
+ for (Resource constraint : g.getObjects(connectionType, STR.HasConnectionConstraint)) {\r
+ IConnectionConstraint cc = g.adapt(constraint, IConnectionConstraint.class);\r
+ switch(cc.isLegal(g, terminals)) {\r
+ case ILLEGAL:\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(" " + cc.getClass().getSimpleName() +\r
+ " -> ILLEGAL");\r
+ return ConnectionJudgementType.ILLEGAL;\r
+ case CANBEMADELEGAL:\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(" " + cc.getClass().getSimpleName() +\r
+ " -> CANBEMADELEGAL");\r
+ legal = false;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ return legal ? ConnectionJudgementType.LEGAL : ConnectionJudgementType.CANBEMADELEGAL;\r
+ }\r
+\r
+ @Override\r
+ public ConnectionJudgement judgeConnection(ReadGraph g,\r
+ Collection<IConnectionPoint> connectionPoints)\r
+ throws DatabaseException {\r
+ \r
+ return judgeConnection(g, connectionPoints, false);\r
+ \r
+ }\r
+\r
+ @Override\r
+ public Resource computeConnectionType(ReadGraph g,\r
+ Collection<IConnectionPoint> connectionPoints)\r
+ throws DatabaseException {\r
+\r
+ return judgeConnection(g, connectionPoints, true).connectionType;\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public IAttachmentRelationMap getAttachmentRelations(ReadGraph g,\r
+ Resource connection) {\r
+ return StandardAttachmentRelationMap.INSTANCE;\r
+ }\r
+\r
+ @Override\r
+ public Set<CPTerminal> resolveTerminals(ReadGraph g, Collection<IConnectionPoint> connectionPoints) \r
+ throws DatabaseException {\r
+ Set<CPTerminal> terminals = new THashSet<CPTerminal>();\r
+ StructuralResource2 STR = StructuralResource2.getInstance(g);\r
+ for(IConnectionPoint cp : connectionPoints) {\r
+ if(Policy.DEBUG_STANDARD_MODELING_RULES)\r
+ System.out.println(this + ": translate connection point: " + cp.toString(g));\r
+ if(cp instanceof CPTerminal)\r
+ terminals.add((CPTerminal)cp);\r
+ else if(cp instanceof CPConnection) {\r
+ CPConnection connection = (CPConnection)cp;\r
+ for (Resource c : StructuralUtils.getRelatedConnections(g, connection.connection)) {\r
+ for (Statement stat : g.getStatements(c, STR.Connects))\r
+ terminals.add(new CPTerminal(stat.getObject(),\r
+ g.getInverse(stat.getPredicate())));\r
+ Resource inf = g.getPossibleObject(c, STR.Binds);\r
+ // TODO: figure out a better component\r
+ if(inf != null) terminals.add(new CPTerminal(inf, inf));\r
+ }\r
+ }\r
+ else if(cp instanceof CPConnectionJoin) {\r
+ CPConnectionJoin connectionJoin = (CPConnectionJoin)cp;\r
+ for (Resource c : StructuralUtils.getRelatedConnectionsOfConnectionJoin(g, connectionJoin.connectionJoin))\r
+ for (Statement stat : g.getStatements(c, STR.Connects))\r
+ terminals.add(new CPTerminal(stat.getObject(),\r
+ g.getInverse(stat.getPredicate())));\r
+ }\r
+ else\r
+ throw new IllegalArgumentException("Connection point " + cp + " encountered.");\r
+ }\r
+ \r
+ return terminals;\r
+ \r
+ }\r
+ \r
+}\r