/******************************************************************************* * 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(); }