--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2014, 2015 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
+ * Semantum Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling;\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.modelingRules.AllowedConnectionTypes;\r
+import org.simantics.utils.ObjectUtils;\r
+import org.simantics.utils.datastructures.Triple;\r
+\r
+/**\r
+ * @author Antti Villberg\r
+ */\r
+public class MigrateModel {\r
+\r
+ public static class MigrationOperation {\r
+ \r
+ public NamedResource instanceToMigrate;\r
+ public NamedResource targetType;\r
+ public NamedResource targetSymbol;\r
+ \r
+ public MigrationOperation(NamedResource nr, NamedResource targetType, NamedResource targetSymbol) {\r
+ this.instanceToMigrate = nr;\r
+ this.targetType = targetType;\r
+ this.targetSymbol = targetSymbol;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ return instanceToMigrate.getName();\r
+ }\r
+ \r
+ public String getDescription(ReadGraph graph) throws DatabaseException {\r
+ String sourceURI = graph.getPossibleURI(instanceToMigrate.getResource());\r
+ if(sourceURI == null) sourceURI = NameUtils.getSafeName(graph, instanceToMigrate.getResource());\r
+ sourceURI = sourceURI.replace("http://Projects/Development%20Project/", "");\r
+ if(targetSymbol != null) {\r
+ String targetURI = graph.getURI(targetSymbol.getResource());\r
+ return sourceURI + " into " + targetURI;\r
+ } else {\r
+ String targetURI = graph.getURI(targetType.getResource());\r
+ return sourceURI + " into " + targetURI;\r
+ }\r
+ }\r
+ \r
+ private Resource getPossibleReplacement(ReadGraph graph, Resource type, Resource predicate) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ String name = graph.getPossibleRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ if(name == null) return null;\r
+ Resource child = Layer0Utils.getPossibleChild(graph, type, name);\r
+ if(child != null) return child;\r
+ for(Resource r : graph.getObjects(type, L0.DomainOf)) {\r
+ String rName = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);\r
+ if(name.equals(rName)) return r;\r
+ }\r
+ return null; \r
+ }\r
+ \r
+ public String replace(WriteGraph graph, Resource instanceToMigrate, Resource type) throws DatabaseException {\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ Collection<Resource> currentTypes = graph.getPrincipalTypes(instanceToMigrate);\r
+ if(currentTypes.size() == 1 && currentTypes.contains(type)) return null;\r
+ \r
+ StringBuilder problems = new StringBuilder();\r
+ \r
+ // Validate operation\r
+ for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {\r
+\r
+ Resource predicate = stm.getPredicate();\r
+ if(stm.isAsserted(instanceToMigrate)) continue;\r
+ \r
+ if(graph.isInstanceOf(predicate, STR.Property)) {\r
+ Resource replacement = getPossibleReplacement(graph, type, predicate);\r
+ // OK for a property to disappear\r
+ if(replacement == null) continue;\r
+ if(!graph.isInstanceOf(replacement, STR.Property)) {\r
+ String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ problems.append(" " + name + " was a property in the source type\n");\r
+ continue;\r
+ }\r
+ String sourceValueType = graph.getPossibleRelatedValue(predicate, L0.RequiresValueType, Bindings.STRING);\r
+ String replacementValueType = graph.getPossibleRelatedValue(replacement, L0.RequiresValueType, Bindings.STRING);\r
+ if(!ObjectUtils.objectEquals(sourceValueType, replacementValueType)) {\r
+ String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ problems.append(" value types for property " + name + " differ (" + sourceValueType + " vs. " + replacementValueType + ")\n");\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if(graph.isInstanceOf(predicate, STR.ConnectionRelation)) {\r
+ Resource replacement = getPossibleReplacement(graph, type, predicate);\r
+ if(replacement == null) {\r
+ String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ problems.append(" used connection point " + name + " has been removed from target type\n");\r
+ continue;\r
+ }\r
+ if(!graph.isInstanceOf(replacement, STR.ConnectionRelation)) {\r
+ String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ problems.append(" " + name + " was a connection point in the source type\n");\r
+ continue;\r
+ }\r
+\r
+ Collection<Resource> sourceConnetionTypes = graph.syncRequest(new AllowedConnectionTypes(predicate));\r
+ Collection<Resource> replacementConnectionTypes = graph.syncRequest(new AllowedConnectionTypes(replacement));\r
+ \r
+ Set<Resource> sourceSet = new THashSet<>(sourceConnetionTypes);\r
+ Set<Resource> replacementSet = new THashSet<>(replacementConnectionTypes);\r
+ \r
+ if(!sourceSet.equals(replacementSet)) {\r
+ String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);\r
+ problems.append(" allowed connection types for connection point " + name + " differ (" + NameUtils.getSafeName(graph, sourceSet) + " vs. " + NameUtils.getSafeName(graph, replacementSet) + ")\n");\r
+ continue;\r
+ }\r
+\r
+ }\r
+ \r
+ }\r
+ \r
+ if(problems.length() > 0) {\r
+ return problems.toString();\r
+ }\r
+\r
+ // Perform operation\r
+ for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {\r
+\r
+ Resource predicate = stm.getPredicate();\r
+ if(stm.isAsserted(instanceToMigrate)) continue;\r
+ \r
+ if(L0.InstanceOf.equals(predicate)) {\r
+ graph.deny(stm);\r
+ graph.claim(instanceToMigrate, L0.InstanceOf, type);\r
+ }\r
+ \r
+ if(graph.isInstanceOf(predicate, STR.Property) || graph.isInstanceOf(predicate, STR.ConnectionRelation)) {\r
+ Resource replacement = getPossibleReplacement(graph, type, predicate);\r
+ graph.deny(stm);\r
+ if(replacement == null) continue;\r
+ graph.claim(stm.getSubject(), replacement, stm.getObject());\r
+ }\r
+ \r
+ }\r
+ \r
+ return null;\r
+\r
+ }\r
+ \r
+ public String perform(WriteGraph graph) throws DatabaseException {\r
+ \r
+ Resource instance = instanceToMigrate.getResource();\r
+ Resource type = targetType.getResource();\r
+ Resource symbol = targetSymbol != null ? targetSymbol.getResource() : null;\r
+ \r
+ String result = replace(graph, instance, type);\r
+ if(result != null) return result;\r
+ \r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+ Resource element = graph.getPossibleObject(instance, MOD.ComponentToElement);\r
+ if(element == null) return null;\r
+ \r
+ Resource targetSymbol = symbol;\r
+ if(targetSymbol == null) {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+ Resource currentSymbol = graph.getPossibleType(element, DIA.Element);\r
+ if(currentSymbol != null) {\r
+ String currentSymbolName = graph.getRelatedValue(currentSymbol, L0.HasName, Bindings.STRING);\r
+ targetSymbol = Layer0Utils.getPossibleChild(graph, type, DIA.ElementClass, currentSymbolName);\r
+ if(targetSymbol == null)\r
+ return "Did not find symbol '" + currentSymbolName + "' from target type.\n";\r
+ } else {\r
+ // No symbol - fine \r
+ return null;\r
+ }\r
+\r
+ }\r
+ \r
+ return replace(graph, element, targetSymbol);\r
+ \r
+ }\r
+ \r
+ }\r
+\r
+ public int instanceCount = 0;\r
+ public Set<Resource> activeModels = new THashSet<>();\r
+ public List<Triple<String, NamedResource, Collection<MigrationOperation>>> instances = new ArrayList<>();\r
+ public List<MigrationOperation> sortedShownInstances = Collections.emptyList();\r
+\r
+}\r