]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/MigrateModel.java
Enhancements to UC migration.
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / MigrateModel.java
index 8e08d8ce6b2c593aa5b7d96c0bf4d13b89615c49..4e472ded4a5d5198544a2ba6f18189db3d469ad9 100644 (file)
-/*******************************************************************************\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
+/*******************************************************************************
+ * Copyright (c) 2014, 2015 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:
+ *     Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.modeling;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.util.URIStringUtils;
+import org.simantics.datatypes.literal.GUID;
+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.NamedResource;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.Instances;
+import org.simantics.db.layer0.request.ChildrenByIdentifier;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.layer0.Layer0;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.structural2.modelingRules.AllowedConnectionTypes;
+import org.simantics.utils.ObjectUtils;
+import org.simantics.utils.datastructures.Triple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import gnu.trove.set.hash.THashSet;
+
+/**
+ * @author Antti Villberg
+ */
+public class MigrateModel {
+
+       public static final Logger LOGGER = LoggerFactory.getLogger(MigrateModel.class);
+
+       public static class MigrationOperation {
+               
+               public NamedResource instanceToMigrate;
+               public NamedResource targetType;
+               public NamedResource targetSymbol;
+               
+               public MigrationOperation(NamedResource nr, NamedResource targetType, NamedResource targetSymbol) {
+                       this.instanceToMigrate = nr;
+                       this.targetType = targetType;
+                       this.targetSymbol = targetSymbol;
+               }
+               
+               @Override
+               public String toString() {
+                       return instanceToMigrate.getName();
+               }
+               
+               public String getDescription(ReadGraph graph) throws DatabaseException {
+                       String sourceURI = graph.getPossibleURI(instanceToMigrate.getResource());
+                       if(sourceURI == null) sourceURI = NameUtils.getSafeName(graph, instanceToMigrate.getResource());
+                       sourceURI = sourceURI.replace("http://Projects/Development%20Project/", "");
+                       if(targetSymbol != null) {
+                               String targetURI = graph.getURI(targetSymbol.getResource());
+                               return URIStringUtils.unescape(sourceURI) + " into " + URIStringUtils.unescape(targetURI);
+                       } else {
+                               String targetURI = graph.getURI(targetType.getResource());
+                               return URIStringUtils.unescape(sourceURI) + " into " + URIStringUtils.unescape(targetURI);
+                       }
+               }
+               
+               private Resource getPossibleReplacement(ReadGraph graph, Resource type, Resource predicate) throws DatabaseException {
+                       Layer0 L0 = Layer0.getInstance(graph);
+                       
+                       // Try to find a relation with the same GUID
+                       GUID guid = graph.getPossibleRelatedValue(predicate, L0.identifier, GUID.BINDING);
+                       Map<GUID, Resource> children = graph.syncRequest(new ChildrenByIdentifier(type), TransientCacheListener.instance());
+                       Resource replacement = children.get(guid);
+                       if (replacement != null)
+                               return replacement;
+                       
+                       // Fall back to using relation name
+                       String name = graph.getPossibleRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                       if(name == null) return null;
+                       Resource child = Layer0Utils.getPossibleChild(graph, type, name);
+                       if(child != null) return child;
+                       for(Resource r : graph.getObjects(type, L0.DomainOf)) {
+                               String rName = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
+                               if(name.equals(rName)) return r;
+                       }
+                       return null; 
+               }
+               
+               public String replace(WriteGraph graph, Resource instanceToMigrate, Resource type) throws DatabaseException {
+
+                       Layer0 L0 = Layer0.getInstance(graph);
+                       StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+                       Collection<Resource> currentTypes = graph.getPrincipalTypes(instanceToMigrate);
+                       if(currentTypes.size() == 1 && currentTypes.contains(type)) return null;
+                       
+                       StringBuilder problems = new StringBuilder();
+                       
+                       // Validate operation
+                       for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {
+
+                               Resource predicate = stm.getPredicate();
+                               if(stm.isAsserted(instanceToMigrate)) continue;
+                               
+                               if(graph.isInstanceOf(predicate, STR.Property)) {
+                                       Resource replacement = getPossibleReplacement(graph, type, predicate);
+                                       // OK for a property to disappear
+                                       if(replacement == null) continue;
+                                       if(!graph.isInstanceOf(replacement, STR.Property)) {
+                                               String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                                               problems.append(" " + name + " was a property in the source type\n");
+                                               continue;
+                                       }
+                                       
+                                       String sourceValueType = graph.getPossibleRelatedValue(predicate, L0.RequiresValueType, Bindings.STRING);
+                                       String replacementValueType = graph.getPossibleRelatedValue(replacement, L0.RequiresValueType, Bindings.STRING);
+                                       if(!ObjectUtils.objectEquals(sourceValueType, replacementValueType)) {
+                                               String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                                               problems.append(" value types for property " + name + " differ (" + sourceValueType + " vs. " + replacementValueType + ")\n");
+                                               continue;
+                                       }
+                               }
+
+                               if(graph.isInstanceOf(predicate, STR.ConnectionRelation)) {
+                                       Resource replacement = getPossibleReplacement(graph, type, predicate);
+                                       if(replacement == null) {
+                                               String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                                               problems.append(" used connection point " + name + " has been removed from target type\n");
+                                               continue;
+                                       }
+                                       if(!graph.isInstanceOf(replacement, STR.ConnectionRelation)) {
+                                               String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                                               problems.append(" " + name + " was a connection point in the source type\n");
+                                               continue;
+                                       }
+
+                                       Collection<Resource> sourceConnetionTypes = graph.syncRequest(new AllowedConnectionTypes(predicate));
+                                       Collection<Resource> replacementConnectionTypes = graph.syncRequest(new AllowedConnectionTypes(replacement));
+                                       
+                                       Set<Resource> sourceSet = new THashSet<>(sourceConnetionTypes);
+                                       Set<Resource> replacementSet = new THashSet<>(replacementConnectionTypes);
+                                       
+                                       if(!sourceSet.equals(replacementSet)) {
+                                               String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
+                                               problems.append(" allowed connection types for connection point " + name + " differ (" + NameUtils.getSafeName(graph, sourceSet) + " vs. " + NameUtils.getSafeName(graph, replacementSet) + ")\n");
+                                               continue;
+                                       }
+
+                               }
+                               
+                       }
+                       
+                       if(problems.length() > 0) {
+                               return problems.toString();
+                       }
+
+                       // Perform operation
+                       for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {
+
+                               Resource predicate = stm.getPredicate();
+                               if(stm.isAsserted(instanceToMigrate)) continue;
+                                               
+                               if(L0.InstanceOf.equals(predicate)) {
+                                       graph.deny(stm);
+                                       graph.claim(instanceToMigrate, L0.InstanceOf, type);
+                               }
+                               
+                               if(graph.isInstanceOf(predicate, STR.Property) || graph.isInstanceOf(predicate, STR.ConnectionRelation)) {
+                                       Resource replacement = getPossibleReplacement(graph, type, predicate);
+                                       graph.deny(stm);
+                                       if(replacement == null) continue;
+                                       
+                                       // Filter out incompatible literal types.
+                                       // TODO: Show warning in UI
+                                       Resource object = stm.getObject();
+                                       Resource replacementRange = graph.getPossibleObject(replacement, L0.HasRange);
+                                       if (replacementRange != null && !graph.isInstanceOf(object, replacementRange)) {
+                                               String instanceName = graph.getPossibleRelatedValue(instanceToMigrate, L0.HasName);
+                                               if (instanceName == null) instanceName = "<unknown>";
+                                               
+                                               String rangeName = graph.getPossibleRelatedValue(replacementRange, L0.HasName);
+                                               if (rangeName == null) rangeName = "<unknown>";
+                                               
+                                               Resource literalType= graph.getPossibleType(object, L0.Value);
+                                               String literalTypeName = literalType != null ? graph.getPossibleRelatedValue(literalType, L0.HasName) : null;
+                                               if (literalTypeName == null) literalTypeName = "<unknown>";
+                                               
+                                               String replacementName = graph.getRelatedValue(replacement, L0.HasName);
+                                               LOGGER.warn("{}: Ignored incompatible value of type {} for predicate {} with range {}", instanceName, literalTypeName, replacementName, rangeName);
+                                               
+                                               continue;
+                                       }
+                                       
+                                       graph.claim(stm.getSubject(), replacement, object);
+                               }
+                               
+                       }
+                       
+                       return null;
+
+               }
+               
+               public String perform(WriteGraph graph) throws DatabaseException {
+                       
+                       Resource instance = instanceToMigrate.getResource();
+                       Resource type = targetType.getResource();
+                       Resource symbol = targetSymbol != null ? targetSymbol.getResource() : null;
+                       
+                       String result = replace(graph, instance, type);
+                       if(result != null) return result;
+                       
+                       ModelingResources MOD = ModelingResources.getInstance(graph);
+                       Resource element = graph.getPossibleObject(instance, MOD.ComponentToElement);
+                       if(element == null) return null;
+                       
+                       Resource targetSymbol = symbol;
+                       if(targetSymbol == null) {
+                               Layer0 L0 = Layer0.getInstance(graph);
+                               DiagramResource DIA = DiagramResource.getInstance(graph);
+                               Resource currentSymbol = graph.getPossibleType(element, DIA.Element);
+                               if(currentSymbol != null) {
+                                       String currentSymbolName = graph.getRelatedValue(currentSymbol, L0.HasName, Bindings.STRING);
+                                       targetSymbol = Layer0Utils.getPossibleChild(graph, type, DIA.ElementClass, currentSymbolName);
+                                       if(targetSymbol == null)
+                                               return "Did not find symbol '" + currentSymbolName + "' from target type.\n";
+                               } else {
+                                       // No symbol - fine 
+                                       return null;
+                               }
+
+                       }
+                       
+                       return replace(graph, element, targetSymbol);
+                       
+               }
+               
+       }
+
+       public int instanceCount = 0;
+       public Set<Resource> activeModels = new THashSet<>();
+       public List<Triple<String, NamedResource, Collection<MigrationOperation>>> instances = new ArrayList<>();
+       public List<MigrationOperation> sortedShownInstances = Collections.emptyList();
+
+       public static void changeComponentType(WriteGraph graph, Resource instance, Resource newComponentType) throws DatabaseException {
+           ModelingResources MOD = ModelingResources.getInstance(graph);
+           Resource newSymbol = graph.getSingleObject(newComponentType, MOD.ComponentTypeToSymbol);
+           new MigrationOperation(new NamedResource("", instance), new NamedResource("", newComponentType), new NamedResource("", newSymbol))
+           .perform(graph);
+       }
+
+       public static void changeAllComponentTypes(WriteGraph graph, Resource model, Resource oldComponentType, Resource newComponentType) throws DatabaseException {
+           ModelingResources MOD = ModelingResources.getInstance(graph);
+           NamedResource newComponentTypeN = new NamedResource("", newComponentType);
+        Resource newSymbol = graph.getSingleObject(newComponentType, MOD.ComponentTypeToSymbol);
+        NamedResource newSymbolN = new NamedResource("", newSymbol);
+        
+           Collection<Resource> instances = graph.adapt(oldComponentType, Instances.class).find(graph, model);
+           
+           for(Resource instance : instances) {
+               new MigrationOperation(
+                       new NamedResource("", instance),
+                       newComponentTypeN,
+                       newSymbolN)
+               .perform(graph);
+           }
+       }
+
+}