]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/adapters/Removers.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / adapters / Removers.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.adapters;
13
14 import gnu.trove.set.hash.THashSet;
15
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.simantics.databoard.Bindings;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.common.NamedResource;
26 import org.simantics.db.common.request.PossibleIndexRoot;
27 import org.simantics.db.common.request.PossibleObjectWithType;
28 import org.simantics.db.common.utils.NameUtils;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.exception.VariableException;
31 import org.simantics.db.layer0.request.PossibleModel;
32 import org.simantics.db.layer0.variable.RVI;
33 import org.simantics.db.layer0.variable.Variable;
34 import org.simantics.db.layer0.variable.Variables;
35 import org.simantics.diagram.content.ConnectionUtil;
36 import org.simantics.diagram.stubs.DiagramResource;
37 import org.simantics.layer0.Layer0;
38 import org.simantics.modeling.ModelingResources;
39 import org.simantics.operation.Layer0X;
40 import org.simantics.scl.runtime.function.Function;
41 import org.simantics.structural.stubs.StructuralResource2;
42 import org.simantics.utils.ui.ErrorLogger;
43
44 /**
45  * @author Tuukka Lehtonen
46  */
47 final class Removers {
48
49     public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException {
50         DiagramResource DIA = DiagramResource.getInstance(graph);
51
52         for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) {
53             ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null);
54             if (!result.inUse())
55                 continue;
56             return result;
57         }
58         return new ValidationResult();
59     }
60
61     public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException {
62         Layer0 L0 = Layer0.getInstance(graph);
63         StructuralResource2 STR = StructuralResource2.getInstance(graph);
64
65         ValidationResult result = new ValidationResult();
66
67         // This is a connection point of a structural component type configuration.
68         String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation);
69         result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation);
70         if (diagramConnectionRelation != null) {
71             String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation);
72             result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation);
73         }
74
75         // 1. Get component type
76         Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) );
77         if (componentType == null)
78             return result;
79         String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING);
80         if (componentTypeName == null)
81             return result;
82         result.componentType = new NamedResource(componentTypeName, componentType);
83
84         // 2. Find index roots that may contain references to this component type
85         Set<Resource> indexRoots = new THashSet<Resource>();
86         Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) );
87         if (indexRoot == null)
88             return result;
89         String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING);
90         if (indexRootName == null)
91             return result;
92         result.containingIndexRoot = new NamedResource(indexRootName, indexRoot);
93
94         Resource model = graph.sync( new PossibleModel(indexRoot) );
95         if (model == null) {
96             // Need to look for references in all models that use this shared library.
97             indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) );
98         } else {
99             // The component type is in a model, other models can't reference it.
100             indexRoots.add(model);
101         }
102
103         // 3. Check whether this connection point is in use in any
104         // instances of this component type within the containing model.
105         for (Resource root : indexRoots) {
106             validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result);
107         }
108
109         return result;
110     }
111
112     private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException {
113         String rootURI = graph.getPossibleURI(root);
114         if (rootURI == null)
115             return;
116
117         Layer0 L0 = Layer0.getInstance(graph);
118         String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING);
119         if (rootName == null)
120             return;
121         NamedResource namedRoot = new NamedResource(rootName, root);
122
123         @SuppressWarnings("rawtypes")
124         Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);
125         @SuppressWarnings("unchecked")
126         List<Map<String, Object>> rows = (List<Map<String, Object>>) modules.apply(graph, root, "Types:\"" + result.componentType.getName() + "\"");
127         if (rows.isEmpty())
128             return;
129
130         ModelingResources MOD = ModelingResources.getInstance(graph);
131         StructuralResource2 STR = StructuralResource2.getInstance(graph);
132
133         for (Map<String, Object> row : rows) {
134             Resource component = (Resource) row.get("Resource");
135             if (graph.isInstanceOf(component, result.componentType.getResource())) {
136                 String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
137                 next_connection:
138                     for (Resource connection : graph.getObjects(component, connectionRelation)) {
139                         if (graph.isInstanceOf(connection, STR.Connection)) {
140
141                             if (diagramConnectionRelation != null) {
142                                 // When diagram connection relation is defined, validate that
143                                 // exactly the specified diagram connection relation is being
144                                 // used and not some other relation from another symbol.
145                                 for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) {
146                                     for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) {
147                                         Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector);
148                                         if (diagramConnection == null)
149                                             continue;
150                                         Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
151                                         Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial);
152                                         if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) {
153                                             addUse(graph, component, componentName, namedRoot, rootURI, result);
154                                             continue next_connection;
155                                         }
156                                     }
157                                 }
158                             } else {
159                                 addUse(graph, component, componentName, namedRoot, rootURI, result);
160                             }
161                         }
162
163                     }
164             }
165         }
166     }
167
168     private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException {
169         String uri = null;
170         try {
171             Variable variable = Variables.getVariable(graph, component);
172             if (!result.usedVariables.add(variable))
173                 return false;
174
175             Use use = new Use();
176             use.resource = component;
177             use.name = componentName;
178             use.variable = variable;
179             use.root = namedRoot;
180             uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, "");
181             use.context = Variables.getPossibleContext(graph, use.variable);
182             if (use.context != null) {
183                 use.path = Variables.getPossibleRVI2(graph, variable);
184             }
185             result.uses.add( use );
186             return true;
187         } catch (VariableException e) {
188             // Might happen with corrupt data, don't panic, just ignore.
189             ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e);
190             return false;
191         }
192     }
193
194     public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException {
195         StringBuilder sb = new StringBuilder();
196         sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.")
197         .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n");
198
199         // See whether the uses contain references from other libraries/models
200         // than the containing index root.
201         boolean absoluteUris = false;
202         for (Use use : result.uses) {
203             if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) {
204                 absoluteUris = true;
205                 break;
206             }
207         }
208
209         for (Use use : result.uses) {
210             if (use.context != null) {
211                 if (absoluteUris) {
212                     sb.append("/").append(use.root.getName()).append(use.rootUri);
213                 } else {
214                     sb.append(use.path.toPossibleString(graph, use.context));
215                 }
216             } else {
217                 if (absoluteUris)
218                     sb.append("/").append(use.root.getName());
219                 sb.append(use.rootUri);
220             }
221             sb.append("\n");
222         }
223         return sb.toString();
224     }
225
226     public static class Use {
227         public String name;
228         public Resource resource;
229         public Variable variable;
230         public Variable context;
231         public RVI path;
232         public NamedResource root;
233         public String rootUri;
234     }
235
236     public static class ValidationResult {
237         public NamedResource containingIndexRoot;
238         public NamedResource componentType;
239         public NamedResource connectionRelation;
240         public NamedResource diagramConnectionRelation;
241         public Set<Variable> usedVariables = new THashSet<Variable>();
242         public Collection<Use> uses = new ArrayList<Use>();
243
244         public boolean inUse() {
245             return !uses.isEmpty();
246         }
247     }
248
249 }