]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.structural2/src/org/simantics/structural2/modelingRules/StandardModelingRules.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.structural2 / src / org / simantics / structural2 / modelingRules / StandardModelingRules.java
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 (file)
index 0000000..a45edf0
--- /dev/null
@@ -0,0 +1,280 @@
+/*******************************************************************************\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