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