]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
99865d007c2258fd182b2c99e75fb60e2bd7a390
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 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.sysdyn.ui.validation;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collections;\r
16 import java.util.List;\r
17 import java.util.Set;\r
18 \r
19 import org.simantics.db.Issue;\r
20 import org.simantics.db.ReadGraph;\r
21 import org.simantics.db.Resource;\r
22 import org.simantics.db.common.utils.NameUtils;\r
23 import org.simantics.db.exception.DatabaseException;\r
24 import org.simantics.db.layer0.variable.Variable;\r
25 import org.simantics.layer0.Layer0;\r
26 import org.simantics.scl.reflection.annotations.SCLValue;\r
27 import org.simantics.sysdyn.SysdynResource;\r
28 import org.simantics.sysdyn.expressionParser.Token;\r
29 import org.simantics.sysdyn.manager.SysdynModel;\r
30 import org.simantics.sysdyn.manager.SysdynModelManager;\r
31 import org.simantics.sysdyn.representation.Configuration;\r
32 import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField;\r
33 import org.simantics.sysdyn.ui.utils.ExpressionUtils;\r
34 import org.simantics.sysdyn.ui.utils.ExpressionUtils.ReferenceOption;\r
35 import org.simantics.sysdyn.ui.utils.SyntaxError;\r
36 import org.simantics.utils.datastructures.collections.CollectionUtils;\r
37 \r
38 /**\r
39  * Evaluates issues related to Dependencies (arrows)\r
40  * \r
41  * @author Teemu Lempinen\r
42  * \r
43  */\r
44 public class DependencyFunction {\r
45         \r
46         // Set containing the names of variables that can be used everywhere, like "time"\r
47         private static Set<String> GLOBAL_VARIABLES = CollectionUtils.toSet("time");\r
48 \r
49     /**\r
50      * Evaluates dependency-related issues for a component.\r
51      * \r
52      * Issues include: Unused dependency\r
53      * \r
54      * @param graph ReadGraph\r
55      * @param component Evaluated component (Variable)\r
56      * @return list of issues related to component\r
57      * @throws DatabaseException\r
58      */\r
59     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")\r
60     public static List<Issue> dependencyValidator(ReadGraph graph, Resource component) throws DatabaseException {\r
61         SysdynResource sr = SysdynResource.getInstance(graph);\r
62         Layer0 l0 = Layer0.getInstance(graph);\r
63 \r
64         if (!graph.isInstanceOf(component, sr.IndependentVariable))\r
65             return Collections.emptyList();\r
66 \r
67         if (!graph.hasStatement(component) || !graph.hasStatement(component, l0.PartOf))\r
68             return Collections.emptyList();\r
69         \r
70         ArrayList<Issue> result = new ArrayList<Issue>();\r
71         Set<String> references = null;\r
72         \r
73         // Find all references in equations of component\r
74         try {\r
75             references = ValidationUtils.getAllReferences(graph, component).getVariableReferences();\r
76         } catch (Exception e) {\r
77             return result;\r
78         } \r
79 \r
80         // Find all variables that are linked to component with arrows\r
81         Set<String> dependencies = ValidationUtils.getDependencies(graph, component);\r
82 \r
83         // Check that all arrow dependencies are used in equations\r
84         if (dependencies != null) {\r
85             for (String dependency : dependencies) {\r
86                 if (references == null || !references.contains(dependency)) {\r
87                     result.add(new IssueWithStringContext(sr.Validations_UnusedDependencyIssue, component, dependency));\r
88                 }\r
89             }\r
90         }\r
91 \r
92         return result;\r
93     }\r
94     \r
95 \r
96     private static Configuration getConfiguration(ReadGraph graph, Resource component) throws DatabaseException {\r
97         Resource configuration = graph.getPossibleObject(component, Layer0.getInstance(graph).PartOf);\r
98         \r
99         if(configuration == null)\r
100             return null;\r
101         \r
102         SysdynModelManager smm = SysdynModelManager.getInstance(graph.getSession());\r
103         SysdynModel sm = smm.getModel(graph, configuration);\r
104         if(sm == null)\r
105             return null;\r
106 \r
107         sm.update(graph);\r
108         return sm.getConfiguration();\r
109     }\r
110 \r
111     /**\r
112      * Evaluates dependency-related issues for a component.\r
113      * \r
114      * Issues include: Missing link No such variable\r
115      * \r
116      * @param graph ReadGraph\r
117      * @param component Evaluated component (Variable)\r
118      * @return list of issues related to component\r
119      * @throws DatabaseException\r
120      */\r
121     @SCLValue(type = "ReadGraph -> Resource -> [Issue]")\r
122     public static List<Issue> missingDependencyValidator(ReadGraph graph, Resource component) throws DatabaseException {\r
123         SysdynResource sr = SysdynResource.getInstance(graph);\r
124         Layer0 l0 = Layer0.getInstance(graph);\r
125 \r
126         if (!graph.isInstanceOf(component, sr.IndependentVariable))\r
127             return Collections.emptyList();\r
128 \r
129         if (!graph.hasStatement(component) || !graph.hasStatement(component, l0.PartOf))\r
130             return Collections.emptyList();\r
131 \r
132         // Find all references in equations of component\r
133         References references = null;\r
134         try {\r
135             references = ValidationUtils.getAllReferences(graph, component);\r
136         } catch (Exception e) {\r
137             return Collections.emptyList();\r
138         }\r
139         \r
140         Configuration configuration = getConfiguration(graph, component);\r
141         ArrayList<Issue> result = new ArrayList<Issue>();\r
142         \r
143         // Examine possible for-index references. Remove if found\r
144         for(Resource expressionResource : references.forIndices.keySet()) {\r
145             if(references.forIndices.containsKey(expressionResource)) {\r
146                 for(Token token : references.forIndices.get(expressionResource).keySet()) {\r
147                     if(references.references.containsKey(expressionResource) && \r
148                             references.references.get(expressionResource).containsKey(token.image)) {\r
149                         references.references.get(expressionResource).remove(token.image);\r
150                     }\r
151                 }\r
152             }\r
153         }\r
154         \r
155         // Examine Sheet references\r
156         for(Resource expressionResource : references.functionReferences.keySet()) {\r
157             for(String functionKey : references.functionReferences.get(expressionResource).keySet()) {\r
158                 List<SyntaxError> sheetErrors = ExpressionUtils.examineSheetReferences(\r
159                         configuration, \r
160                         functionKey, \r
161                         references.functionReferences.get(expressionResource).get(functionKey), \r
162                         references.expressions.get(expressionResource), \r
163                         references.references.get(expressionResource));\r
164                 if(sheetErrors != null) {\r
165                     for(SyntaxError error : sheetErrors)\r
166                         result.add(new IssueWithStringContext(sr.Validations_InvalidSheetReferenceIssue, component, error.getMessage(), error.getImage()));\r
167                 }\r
168             }\r
169         }\r
170         \r
171         \r
172         // Examine dependencies\r
173         Set<String> variablesReferences = references.getVariableReferences();\r
174         if(variablesReferences == null || variablesReferences.isEmpty())\r
175             return result;\r
176         \r
177         // Remove references to self\r
178         String name = NameUtils.getSafeName(graph, component);\r
179         if(name != null && variablesReferences.contains(name))\r
180             variablesReferences.remove(name);\r
181         \r
182         // Find all variables that are linked to component with arrows\r
183         Set<String> dependencies = ValidationUtils.getDependencies(graph, component);\r
184         dependencies.addAll(GLOBAL_VARIABLES);\r
185         \r
186         // Remove all dependency variables from reference maps \r
187         for(String dependency : dependencies)\r
188             variablesReferences.remove(dependency);\r
189 \r
190         boolean isStock = isStock(graph, component);\r
191         ReferenceOption option;\r
192 \r
193         for(String reference : variablesReferences) {\r
194             option = ExpressionUtils.getReferenceOption(configuration, reference);\r
195             switch(option) {\r
196                 case DOES_NOT_EXIST:\r
197                     result.add(new IssueWithStringContext(sr.Validations_NoSuchVariableIssue, component, reference));\r
198                 case CAN_BE_CONNECTED:\r
199                     if(isStock) {\r
200                         /* Stocks do not get incoming dependencies. They are allowed\r
201                         to have references without arrows */\r
202                     } else {\r
203                         result.add(new IssueWithStringContext(sr.Validations_MissingLinkIssue, component, reference));\r
204                     }\r
205                     break;\r
206                 case CANNOT_BE_CONNECTED:\r
207             }\r
208         }\r
209         \r
210         \r
211         for(Resource expression : references.ranges.keySet()) {\r
212             List<SyntaxError> errors = new ArrayList<SyntaxError>();\r
213             // RANGES\r
214             errors.addAll(ExpressionUtils.examineArrayRanges(graph, configuration, references.ranges.get(expression), references.forIndices.get(expression)));\r
215             \r
216             // ENUMERATION REFERENCES IN FOR-LOOPS\r
217             errors.addAll(ExpressionUtils.examineEnumerationReferences(configuration, references.enumerationReferences.get(expression)));\r
218 \r
219             for(SyntaxError error : errors) {\r
220                 Resource type = sr.Validations_RangeIssue;\r
221                 if(ExpressionField.SYNTAX_WARNING.equals(error.getType())) {\r
222                     type = sr.Validations_RangeWarning;\r
223                 }\r
224                 result.add(new IssueWithStringContext(type, component, error.getMessage()));\r
225 \r
226             }\r
227         }   \r
228         \r
229         return result;\r
230 \r
231     }\r
232     \r
233     private static boolean isStock(ReadGraph graph, Resource variable) throws DatabaseException {\r
234         List<Resource> expressionList = ValidationUtils.getExpressions(graph, variable);\r
235         if(expressionList == null || expressionList.isEmpty()) {\r
236             return false;\r
237         } else {\r
238             for(Resource expression : expressionList) {\r
239                 if(!graph.isInstanceOf(expression, SysdynResource.getInstance(graph).StockExpression))\r
240                     return false;\r
241             }\r
242             return true;\r
243         }\r
244     }\r
245 \r
246     /**\r
247      * Missing link description\r
248      * \r
249      * @param graph ReadGraph\r
250      * @param converter\r
251      * @param issue Issue\r
252      * @return issue description\r
253      * @throws DatabaseException\r
254      */\r
255     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
256     public static String missingLinkIssueDescription(ReadGraph graph, Resource converter, Variable property)\r
257             throws DatabaseException {\r
258         \r
259         List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);\r
260         String result = "Missing a link to ";\r
261         if (contexts.size() > 0) {\r
262             result = result + contexts.get(0);\r
263         }\r
264 \r
265         return result;\r
266         \r
267     }\r
268 \r
269     /**\r
270      * Unused dependency description\r
271      * \r
272      * @param graph ReadGraph\r
273      * @param converter\r
274      * @param issue Issue\r
275      * @return issue description\r
276      * @throws DatabaseException\r
277      */\r
278     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
279     public static String unusedDependencyIssueDescription(ReadGraph graph, Resource converter, Variable property)\r
280             throws DatabaseException {\r
281         \r
282         List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);\r
283         String result = "Unused dependency: ";\r
284         if (contexts.size() > 0) {\r
285             result = result + contexts.get(0);\r
286         }\r
287 \r
288         return result;\r
289     }\r
290 \r
291     /**\r
292      * No such variable description. Finds all variables that the component\r
293      * refers to and adds their names to the issue description.\r
294      * \r
295      * @param graph ReadGraph\r
296      * @param converter\r
297      * @param issue Issue\r
298      * @return issue description\r
299      * @throws DatabaseException\r
300      */\r
301     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
302     public static String noSuchVariableIssueDescription(ReadGraph graph, Resource converter, Variable property)\r
303             throws DatabaseException {\r
304         \r
305         List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);\r
306         String result = "Refers to unexisting variable ";\r
307         if (contexts.size() > 0) {\r
308             result = result + contexts.get(0);\r
309         }\r
310         \r
311         return result;\r
312     }\r
313     \r
314     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
315     public static String invalidSheetReferenceIssueDescription(ReadGraph graph, Resource converter, Variable property)\r
316             throws DatabaseException {\r
317         \r
318         List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);\r
319         String result = "";\r
320         \r
321         if(contexts.size() == 2)\r
322             result = contexts.get(0) + ": " + contexts.get(1);\r
323         else\r
324             result = "Spreadsheet reference error";\r
325 \r
326         return result;\r
327     }\r
328     \r
329     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
330     public static String rangeIssueDescription(ReadGraph graph, Resource converter, Variable property)\r
331             throws DatabaseException {\r
332         \r
333         List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);\r
334         if (contexts.size() > 0) {\r
335             return contexts.get(0);\r
336         } else {\r
337             return "Range Issue";\r
338         }\r
339     }\r
340     \r
341     @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")\r
342     public static String rangeWarningDescription(ReadGraph graph, Resource converter, Variable property)\r
343             throws DatabaseException {\r
344         return rangeIssueDescription(graph, converter, property);\r
345     }\r
346     \r
347     \r
348     \r
349     \r
350 }\r