X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2FMigrateModel.java;h=4e472ded4a5d5198544a2ba6f18189db3d469ad9;hp=fe385a6a12b5028545c85af277fa8dbc3492e176;hb=b055bfb36cca301ceed0591028d245e152c8c32d;hpb=602614f4502aae85ecf3967abb7152d2d62903e3 diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/MigrateModel.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/MigrateModel.java index fe385a6a1..4e472ded4 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/MigrateModel.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/MigrateModel.java @@ -1,219 +1,284 @@ -/******************************************************************************* - * 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 gnu.trove.set.hash.THashSet; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import org.simantics.databoard.Bindings; -import org.simantics.databoard.util.URIStringUtils; -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.utils.NameUtils; -import org.simantics.db.exception.DatabaseException; -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; - -/** - * @author Antti Villberg - */ -public class MigrateModel { - - 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); - 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 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 sourceConnetionTypes = graph.syncRequest(new AllowedConnectionTypes(predicate)); - Collection replacementConnectionTypes = graph.syncRequest(new AllowedConnectionTypes(replacement)); - - Set sourceSet = new THashSet<>(sourceConnetionTypes); - Set 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; - graph.claim(stm.getSubject(), replacement, stm.getObject()); - } - - } - - 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 activeModels = new THashSet<>(); - public List>> instances = new ArrayList<>(); - public List sortedShownInstances = Collections.emptyList(); - -} +/******************************************************************************* + * 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 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 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 sourceConnetionTypes = graph.syncRequest(new AllowedConnectionTypes(predicate)); + Collection replacementConnectionTypes = graph.syncRequest(new AllowedConnectionTypes(replacement)); + + Set sourceSet = new THashSet<>(sourceConnetionTypes); + Set 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 = ""; + + String rangeName = graph.getPossibleRelatedValue(replacementRange, L0.HasName); + if (rangeName == null) rangeName = ""; + + Resource literalType= graph.getPossibleType(object, L0.Value); + String literalTypeName = literalType != null ? graph.getPossibleRelatedValue(literalType, L0.HasName) : null; + if (literalTypeName == null) literalTypeName = ""; + + 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 activeModels = new THashSet<>(); + public List>> instances = new ArrayList<>(); + public List 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 instances = graph.adapt(oldComponentType, Instances.class).find(graph, model); + + for(Resource instance : instances) { + new MigrationOperation( + new NamedResource("", instance), + newComponentTypeN, + newSymbolN) + .perform(graph); + } + } + +}