1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2012 Association for Decentralized Information Management in
\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 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.ui.validation;
\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
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
39 * Evaluates issues related to Dependencies (arrows)
\r
41 * @author Teemu Lempinen
\r
44 public class DependencyFunction {
\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
50 * Evaluates dependency-related issues for a component.
\r
52 * Issues include: Unused dependency
\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
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
64 if (!graph.isInstanceOf(component, sr.IndependentVariable))
\r
65 return Collections.emptyList();
\r
67 if (!graph.hasStatement(component) || !graph.hasStatement(component, l0.PartOf))
\r
68 return Collections.emptyList();
\r
70 ArrayList<Issue> result = new ArrayList<Issue>();
\r
71 Set<String> references = null;
\r
73 // Find all references in equations of component
\r
75 references = ValidationUtils.getAllReferences(graph, component).getVariableReferences();
\r
76 } catch (Exception e) {
\r
80 // Find all variables that are linked to component with arrows
\r
81 Set<String> dependencies = ValidationUtils.getDependencies(graph, component);
\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
96 private static Configuration getConfiguration(ReadGraph graph, Resource component) throws DatabaseException {
\r
97 Resource configuration = graph.getPossibleObject(component, Layer0.getInstance(graph).PartOf);
\r
99 if(configuration == null)
\r
102 SysdynModelManager smm = SysdynModelManager.getInstance(graph.getSession());
\r
103 SysdynModel sm = smm.getModel(graph, configuration);
\r
108 return sm.getConfiguration();
\r
112 * Evaluates dependency-related issues for a component.
\r
114 * Issues include: Missing link No such variable
\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
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
126 if (!graph.isInstanceOf(component, sr.IndependentVariable))
\r
127 return Collections.emptyList();
\r
129 if (!graph.hasStatement(component) || !graph.hasStatement(component, l0.PartOf))
\r
130 return Collections.emptyList();
\r
132 // Find all references in equations of component
\r
133 References references = null;
\r
135 references = ValidationUtils.getAllReferences(graph, component);
\r
136 } catch (Exception e) {
\r
137 return Collections.emptyList();
\r
140 Configuration configuration = getConfiguration(graph, component);
\r
141 ArrayList<Issue> result = new ArrayList<Issue>();
\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
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
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
172 // Examine dependencies
\r
173 Set<String> variablesReferences = references.getVariableReferences();
\r
174 if(variablesReferences == null || variablesReferences.isEmpty())
\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
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
186 // Remove all dependency variables from reference maps
\r
187 for(String dependency : dependencies)
\r
188 variablesReferences.remove(dependency);
\r
190 boolean isStock = isStock(graph, component);
\r
191 ReferenceOption option;
\r
193 for(String reference : variablesReferences) {
\r
194 option = ExpressionUtils.getReferenceOption(configuration, reference);
\r
196 case DOES_NOT_EXIST:
\r
197 result.add(new IssueWithStringContext(sr.Validations_NoSuchVariableIssue, component, reference));
\r
198 case CAN_BE_CONNECTED:
\r
200 /* Stocks do not get incoming dependencies. They are allowed
\r
201 to have references without arrows */
\r
203 result.add(new IssueWithStringContext(sr.Validations_MissingLinkIssue, component, reference));
\r
206 case CANNOT_BE_CONNECTED:
\r
211 for(Resource expression : references.ranges.keySet()) {
\r
212 List<SyntaxError> errors = new ArrayList<SyntaxError>();
\r
214 errors.addAll(ExpressionUtils.examineArrayRanges(graph, configuration, references.ranges.get(expression), references.forIndices.get(expression)));
\r
216 // ENUMERATION REFERENCES IN FOR-LOOPS
\r
217 errors.addAll(ExpressionUtils.examineEnumerationReferences(configuration, references.enumerationReferences.get(expression)));
\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
224 result.add(new IssueWithStringContext(type, component, error.getMessage()));
\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
238 for(Resource expression : expressionList) {
\r
239 if(!graph.isInstanceOf(expression, SysdynResource.getInstance(graph).StockExpression))
\r
247 * Missing link description
\r
249 * @param graph ReadGraph
\r
251 * @param issue Issue
\r
252 * @return issue description
\r
253 * @throws DatabaseException
\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
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
270 * Unused dependency description
\r
272 * @param graph ReadGraph
\r
274 * @param issue Issue
\r
275 * @return issue description
\r
276 * @throws DatabaseException
\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
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
292 * No such variable description. Finds all variables that the component
\r
293 * refers to and adds their names to the issue description.
\r
295 * @param graph ReadGraph
\r
297 * @param issue Issue
\r
298 * @return issue description
\r
299 * @throws DatabaseException
\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
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
314 @SCLValue(type = "ReadGraph -> Resource -> Variable -> String")
\r
315 public static String invalidSheetReferenceIssueDescription(ReadGraph graph, Resource converter, Variable property)
\r
316 throws DatabaseException {
\r
318 List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);
\r
319 String result = "";
\r
321 if(contexts.size() == 2)
\r
322 result = contexts.get(0) + ": " + contexts.get(1);
\r
324 result = "Spreadsheet reference error";
\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
333 List<String> contexts = IssueWithStringContext.getStringContexts(graph, property);
\r
334 if (contexts.size() > 0) {
\r
335 return contexts.get(0);
\r
337 return "Range Issue";
\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