1 /*******************************************************************************
\r
2 * Copyright (c) 2014, 2015 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Semantum Oy - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling;
\r
14 import gnu.trove.set.hash.THashSet;
\r
16 import java.util.ArrayList;
\r
17 import java.util.Collection;
\r
18 import java.util.Collections;
\r
19 import java.util.List;
\r
20 import java.util.Set;
\r
22 import org.simantics.databoard.Bindings;
\r
23 import org.simantics.databoard.util.URIStringUtils;
\r
24 import org.simantics.db.ReadGraph;
\r
25 import org.simantics.db.Resource;
\r
26 import org.simantics.db.Statement;
\r
27 import org.simantics.db.WriteGraph;
\r
28 import org.simantics.db.common.NamedResource;
\r
29 import org.simantics.db.common.utils.NameUtils;
\r
30 import org.simantics.db.exception.DatabaseException;
\r
31 import org.simantics.db.layer0.util.Layer0Utils;
\r
32 import org.simantics.diagram.stubs.DiagramResource;
\r
33 import org.simantics.layer0.Layer0;
\r
34 import org.simantics.structural.stubs.StructuralResource2;
\r
35 import org.simantics.structural2.modelingRules.AllowedConnectionTypes;
\r
36 import org.simantics.utils.ObjectUtils;
\r
37 import org.simantics.utils.datastructures.Triple;
\r
40 * @author Antti Villberg
\r
42 public class MigrateModel {
\r
44 public static class MigrationOperation {
\r
46 public NamedResource instanceToMigrate;
\r
47 public NamedResource targetType;
\r
48 public NamedResource targetSymbol;
\r
50 public MigrationOperation(NamedResource nr, NamedResource targetType, NamedResource targetSymbol) {
\r
51 this.instanceToMigrate = nr;
\r
52 this.targetType = targetType;
\r
53 this.targetSymbol = targetSymbol;
\r
57 public String toString() {
\r
58 return instanceToMigrate.getName();
\r
61 public String getDescription(ReadGraph graph) throws DatabaseException {
\r
62 String sourceURI = graph.getPossibleURI(instanceToMigrate.getResource());
\r
63 if(sourceURI == null) sourceURI = NameUtils.getSafeName(graph, instanceToMigrate.getResource());
\r
64 sourceURI = sourceURI.replace("http://Projects/Development%20Project/", "");
\r
65 if(targetSymbol != null) {
\r
66 String targetURI = graph.getURI(targetSymbol.getResource());
\r
67 return URIStringUtils.unescape(sourceURI) + " into " + URIStringUtils.unescape(targetURI);
\r
69 String targetURI = graph.getURI(targetType.getResource());
\r
70 return URIStringUtils.unescape(sourceURI) + " into " + URIStringUtils.unescape(targetURI);
\r
74 private Resource getPossibleReplacement(ReadGraph graph, Resource type, Resource predicate) throws DatabaseException {
\r
75 Layer0 L0 = Layer0.getInstance(graph);
\r
76 String name = graph.getPossibleRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
77 if(name == null) return null;
\r
78 Resource child = Layer0Utils.getPossibleChild(graph, type, name);
\r
79 if(child != null) return child;
\r
80 for(Resource r : graph.getObjects(type, L0.DomainOf)) {
\r
81 String rName = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
\r
82 if(name.equals(rName)) return r;
\r
87 public String replace(WriteGraph graph, Resource instanceToMigrate, Resource type) throws DatabaseException {
\r
89 Layer0 L0 = Layer0.getInstance(graph);
\r
90 StructuralResource2 STR = StructuralResource2.getInstance(graph);
\r
92 Collection<Resource> currentTypes = graph.getPrincipalTypes(instanceToMigrate);
\r
93 if(currentTypes.size() == 1 && currentTypes.contains(type)) return null;
\r
95 StringBuilder problems = new StringBuilder();
\r
97 // Validate operation
\r
98 for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {
\r
100 Resource predicate = stm.getPredicate();
\r
101 if(stm.isAsserted(instanceToMigrate)) continue;
\r
103 if(graph.isInstanceOf(predicate, STR.Property)) {
\r
104 Resource replacement = getPossibleReplacement(graph, type, predicate);
\r
105 // OK for a property to disappear
\r
106 if(replacement == null) continue;
\r
107 if(!graph.isInstanceOf(replacement, STR.Property)) {
\r
108 String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
109 problems.append(" " + name + " was a property in the source type\n");
\r
112 String sourceValueType = graph.getPossibleRelatedValue(predicate, L0.RequiresValueType, Bindings.STRING);
\r
113 String replacementValueType = graph.getPossibleRelatedValue(replacement, L0.RequiresValueType, Bindings.STRING);
\r
114 if(!ObjectUtils.objectEquals(sourceValueType, replacementValueType)) {
\r
115 String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
116 problems.append(" value types for property " + name + " differ (" + sourceValueType + " vs. " + replacementValueType + ")\n");
\r
121 if(graph.isInstanceOf(predicate, STR.ConnectionRelation)) {
\r
122 Resource replacement = getPossibleReplacement(graph, type, predicate);
\r
123 if(replacement == null) {
\r
124 String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
125 problems.append(" used connection point " + name + " has been removed from target type\n");
\r
128 if(!graph.isInstanceOf(replacement, STR.ConnectionRelation)) {
\r
129 String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
130 problems.append(" " + name + " was a connection point in the source type\n");
\r
134 Collection<Resource> sourceConnetionTypes = graph.syncRequest(new AllowedConnectionTypes(predicate));
\r
135 Collection<Resource> replacementConnectionTypes = graph.syncRequest(new AllowedConnectionTypes(replacement));
\r
137 Set<Resource> sourceSet = new THashSet<>(sourceConnetionTypes);
\r
138 Set<Resource> replacementSet = new THashSet<>(replacementConnectionTypes);
\r
140 if(!sourceSet.equals(replacementSet)) {
\r
141 String name = graph.getRelatedValue(predicate, L0.HasName, Bindings.STRING);
\r
142 problems.append(" allowed connection types for connection point " + name + " differ (" + NameUtils.getSafeName(graph, sourceSet) + " vs. " + NameUtils.getSafeName(graph, replacementSet) + ")\n");
\r
150 if(problems.length() > 0) {
\r
151 return problems.toString();
\r
154 // Perform operation
\r
155 for(Statement stm : graph.getStatements(instanceToMigrate, L0.IsWeaklyRelatedTo)) {
\r
157 Resource predicate = stm.getPredicate();
\r
158 if(stm.isAsserted(instanceToMigrate)) continue;
\r
160 if(L0.InstanceOf.equals(predicate)) {
\r
162 graph.claim(instanceToMigrate, L0.InstanceOf, type);
\r
165 if(graph.isInstanceOf(predicate, STR.Property) || graph.isInstanceOf(predicate, STR.ConnectionRelation)) {
\r
166 Resource replacement = getPossibleReplacement(graph, type, predicate);
\r
168 if(replacement == null) continue;
\r
169 graph.claim(stm.getSubject(), replacement, stm.getObject());
\r
178 public String perform(WriteGraph graph) throws DatabaseException {
\r
180 Resource instance = instanceToMigrate.getResource();
\r
181 Resource type = targetType.getResource();
\r
182 Resource symbol = targetSymbol != null ? targetSymbol.getResource() : null;
\r
184 String result = replace(graph, instance, type);
\r
185 if(result != null) return result;
\r
187 ModelingResources MOD = ModelingResources.getInstance(graph);
\r
188 Resource element = graph.getPossibleObject(instance, MOD.ComponentToElement);
\r
189 if(element == null) return null;
\r
191 Resource targetSymbol = symbol;
\r
192 if(targetSymbol == null) {
\r
193 Layer0 L0 = Layer0.getInstance(graph);
\r
194 DiagramResource DIA = DiagramResource.getInstance(graph);
\r
195 Resource currentSymbol = graph.getPossibleType(element, DIA.Element);
\r
196 if(currentSymbol != null) {
\r
197 String currentSymbolName = graph.getRelatedValue(currentSymbol, L0.HasName, Bindings.STRING);
\r
198 targetSymbol = Layer0Utils.getPossibleChild(graph, type, DIA.ElementClass, currentSymbolName);
\r
199 if(targetSymbol == null)
\r
200 return "Did not find symbol '" + currentSymbolName + "' from target type.\n";
\r
202 // No symbol - fine
\r
208 return replace(graph, element, targetSymbol);
\r
214 public int instanceCount = 0;
\r
215 public Set<Resource> activeModels = new THashSet<>();
\r
216 public List<Triple<String, NamedResource, Collection<MigrationOperation>>> instances = new ArrayList<>();
\r
217 public List<MigrationOperation> sortedShownInstances = Collections.emptyList();
\r