]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/Variables.java
Sync git svn branch with SVN repository r33158.
[simantics/platform.git] / bundles / org.simantics.db.layer0 / src / org / simantics / db / layer0 / variable / Variables.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.layer0.variable;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.LinkedList;\r
18 import java.util.List;\r
19 import java.util.Map;\r
20 \r
21 import org.simantics.databoard.binding.Binding;\r
22 import org.simantics.databoard.binding.mutable.Variant;\r
23 import org.simantics.databoard.type.Datatype;\r
24 import org.simantics.databoard.type.NumberType;\r
25 import org.simantics.databoard.util.URIStringUtils;\r
26 import org.simantics.db.ReadGraph;\r
27 import org.simantics.db.RequestProcessor;\r
28 import org.simantics.db.Resource;\r
29 import org.simantics.db.common.request.PossibleIndexRoot;\r
30 import org.simantics.db.common.request.TernaryRead;\r
31 import org.simantics.db.common.utils.Logger;\r
32 import org.simantics.db.exception.DatabaseException;\r
33 import org.simantics.db.layer0.exception.MissingVariableException;\r
34 import org.simantics.db.layer0.request.Model;\r
35 import org.simantics.db.layer0.request.PossibleActiveVariableFromVariable;\r
36 import org.simantics.db.layer0.request.PossibleVariableIndexRoot;\r
37 import org.simantics.db.layer0.request.PossibleVariableModel;\r
38 import org.simantics.db.layer0.request.PropertyInfo;\r
39 import org.simantics.db.layer0.request.PropertyInfoRequest;\r
40 import org.simantics.db.layer0.request.ResourceURIToVariable;\r
41 import org.simantics.db.layer0.request.VariableIndexRoot;\r
42 import org.simantics.db.layer0.request.VariableURI;\r
43 import org.simantics.layer0.Layer0;\r
44 import org.simantics.operation.Layer0X;\r
45 import org.simantics.project.ontology.ProjectResource;\r
46 import org.simantics.scl.runtime.function.Function1;\r
47 import org.simantics.scl.runtime.function.Function2;\r
48 import org.simantics.scl.runtime.function.Function3;\r
49 import org.simantics.simulation.ontology.SimulationResource;\r
50 import org.simantics.simulator.variable.exceptions.NodeManagerException;\r
51 import org.simantics.utils.datastructures.Pair;\r
52 \r
53 import gnu.trove.map.hash.TObjectIntHashMap;\r
54 \r
55 final public class Variables {\r
56 \r
57     public static final Variant PENDING_NODE_VALUE = new Variant();\r
58 \r
59     public static final NodeStructure PENDING_NODE_STRUCTURE = new NodeStructure(Collections.emptyMap(), Collections.emptyMap()) {\r
60         public boolean equals(Object object) {\r
61             return this == object;\r
62         }\r
63     };\r
64 \r
65     public static enum Role {\r
66 \r
67         CHILD("/"), PROPERTY("#");\r
68 \r
69         transient final String identifier;\r
70 \r
71         private Role(String identifier) {\r
72             this.identifier = identifier;\r
73         }\r
74 \r
75         final public String getIdentifier() {\r
76             return identifier;\r
77         }\r
78 \r
79         public static Role getRole( String identifier ) {\r
80             for (Role role : Role.values()) if (role.identifier.equals( identifier )) return role;\r
81             return null;\r
82         }\r
83 \r
84     }\r
85 \r
86     // use getPredicate\r
87     //final public static String PREDICATE = "PREDICATE";\r
88 \r
89     @Deprecated\r
90     // use getName\r
91     final public static String NAME = "HasName";\r
92     final public static String CLASSIFICATIONS = "classifications";\r
93     final public static String EXPRESSION = "HasExpression";\r
94     final public static String INPUT_VALIDATOR = "HasInputValidator";\r
95     final public static String INPUT_MODIFIER = "HasInputModifier";\r
96     final public static String FORMATTER = "HasFormatter";\r
97 \r
98     final public static String STANDARD_RESOURCE = "hasStandardResource";\r
99     //@Deprecated\r
100     // use getPresents\r
101     //final public static String REPRESENTS = "Represents";\r
102     final public static String TYPE = "Type";\r
103     final public static String URI = "URI";\r
104     /**\r
105      * @deprecated use {@link Variable#getRVI(ReadGraph)} and {@link RVI} instead.\r
106      */\r
107 //    @Deprecated\r
108 //    final public static String SERIALISED = "Serialised";\r
109 //    @Deprecated\r
110     // use getParent\r
111     //final public static String PARENT = "Parent";\r
112     //final public static String ROLE = "Role";\r
113     //final public static String DATATYPE = "DATATYPE";\r
114     //final public static String UNIT = "UNIT";\r
115 \r
116     final public static String VALID = "valid";\r
117     final public static String REQUIRED = "required";\r
118     final public static String DEFAULT = "default";\r
119     final public static String READONLY = "readOnly";\r
120     final public static String VALIDATOR = "validator";\r
121 \r
122     final public static String LABEL = "HasLabel";\r
123 \r
124     final public static String ENUMERATION_VALUES = "HasEnumerationValues";\r
125     final public static String CUSTOM_MODIFIER = "HasCustomModifier";\r
126 \r
127     final public static String DISPLAY_COLUMN = "HasDisplayColumn";\r
128 \r
129     final public static String DISPLAY_PROPERTY = "HasDisplayProperty";\r
130     final public static String DISPLAY_VALUE = "HasDisplayValue";\r
131     final public static String DISPLAY_UNIT = "HasDisplayUnit";\r
132 \r
133     final public static String CONVERTED_VALUE = "convertedValue";\r
134 \r
135     /**\r
136      * This property should exist for array valued property variables.\r
137      */\r
138     final public static String ARRAY_SIZE = "ARRAY_SIZE";\r
139 \r
140 \r
141     @Deprecated\r
142     // use etc. variable.adapt(graph, Interface.class).getResource()\r
143     final public static String RESOURCE = "Resource";\r
144     @Deprecated\r
145     final public static String CONTAINER_RESOURCE = "ContainerResource";\r
146     @Deprecated\r
147     final public static String PROPERTY_RESOURCE = "PROPERTY_RESOURCE";\r
148 \r
149     @Deprecated\r
150     public final static String[] builtins = {\r
151         TYPE, RESOURCE, URI\r
152         //, SERIALISED\r
153     };\r
154 \r
155     public static Variable getPossibleVariable(ReadGraph graph, Resource resource) throws DatabaseException {\r
156         String uri = graph.getPossibleURI(resource);\r
157         return uri != null ? getPossibleVariable(graph, uri) : null;\r
158     }\r
159 \r
160     public static Variable getPossibleVariable(ReadGraph graph, String uri) throws DatabaseException {\r
161         try {\r
162             return getVariable(graph, uri);\r
163         } catch (DatabaseException e) {\r
164             return null;\r
165         }\r
166     }\r
167 \r
168     public static Variable getVariable(ReadGraph graph, Resource resource) throws DatabaseException {\r
169         return getVariable(graph, graph.getURI(resource));\r
170     }\r
171 \r
172     public static Variable getVariable(ReadGraph graph, String uri) throws DatabaseException {\r
173         try {\r
174             return graph.sync(new ResourceURIToVariable(uri));\r
175         } catch (MissingVariableException e) {\r
176             return VariableRepository.get(graph, uri);\r
177         }\r
178     }\r
179 \r
180     private static int commonPrefixLength(String a, String b) {\r
181         int maxC = Math.min(a.length(), b.length());\r
182         for(int c=0;c<maxC;++c) {\r
183             if(a.charAt(c) != b.charAt(c))\r
184                 return c;\r
185         }\r
186         return maxC;\r
187     }\r
188 \r
189     private static boolean isSplitPos(String str, int p) {\r
190         if(p==str.length())\r
191             return true;\r
192         char c = str.charAt(p);\r
193         return c=='/' || c=='#';\r
194     }\r
195 \r
196     private static int pathLength(String path) {\r
197         int count = 0;\r
198         for(int i=0;i<path.length();++i) {\r
199             char c = path.charAt(i);\r
200             if(c=='/' || c=='#')\r
201                 ++count;\r
202         }\r
203         return count;\r
204     }\r
205 \r
206     private static String prefixByParentPath(int parentPathLength, String suffix) {\r
207         StringBuilder b = new StringBuilder();\r
208         for(int i=0;i<parentPathLength;++i)\r
209             b.append('.');\r
210         b.append(suffix);\r
211         return b.toString();\r
212     }\r
213 \r
214     public static String getRVI(ReadGraph graph, Variable base, Variable other) throws DatabaseException {\r
215         String baseURI = graph.syncRequest(new VariableURI(base));\r
216         String otherURI = graph.syncRequest(new VariableURI(other));\r
217         return getRelativeRVI(baseURI, otherURI);\r
218     }\r
219 \r
220     public static String getRelativeRVI(String baseURI, String otherURI) {\r
221         int prefixLength = commonPrefixLength(baseURI, otherURI);\r
222         if(!isSplitPos(baseURI, prefixLength) || !isSplitPos(otherURI, prefixLength)) {\r
223             for(--prefixLength;prefixLength > 0 && !isSplitPos(baseURI, prefixLength);--prefixLength);\r
224         }\r
225         if(prefixLength == baseURI.length())\r
226             return otherURI.substring(prefixLength);\r
227         else \r
228             return prefixByParentPath(\r
229                     pathLength(baseURI.substring(prefixLength)), \r
230                     otherURI.substring(prefixLength));      \r
231     }\r
232 \r
233     public static String getRVI2(ReadGraph graph, Variable base, Variable other) throws DatabaseException {\r
234         TObjectIntHashMap<Variable> baseLength = new TObjectIntHashMap<Variable>();\r
235         for(int depth=0;base != null;base = base.getParent(graph),++depth)\r
236             baseLength.put(base, depth);\r
237         Variable cur;\r
238         for(cur=other;!baseLength.containsKey(cur);cur=cur.getParent(graph));\r
239 \r
240         // To string\r
241         String curURI = cur.getURI(graph);\r
242         String otherURI = other.getURI(graph);\r
243 \r
244         return prefixByParentPath(baseLength.get(cur), otherURI.substring(curURI.length()));\r
245     }\r
246 \r
247     public static String getProjectRVI(ReadGraph graph, Variable variable) throws DatabaseException {\r
248         Resource project = getProject(graph, variable);\r
249         String projectURI = graph.getURI(project);\r
250         return variable.getURI(graph).substring(projectURI.length());\r
251     }\r
252 \r
253     private static int getSegmentEnd(String suffix) {\r
254         int pos;\r
255         for(pos=1;pos<suffix.length();++pos) {\r
256             char c = suffix.charAt(pos);\r
257             if(c == '/' || c == '#')\r
258                 break;\r
259         }\r
260         return pos;\r
261     }\r
262 \r
263     public static String getRVI(String rvi, String suffix) throws DatabaseException {\r
264         if(suffix.isEmpty()) return rvi;\r
265         switch(suffix.charAt(0)) {\r
266             case '.': {\r
267                 return getRVI(URIStringUtils.getRVIParent(rvi), suffix.substring(1));\r
268             }\r
269             case '#': {\r
270                 int segmentEnd = getSegmentEnd(suffix);\r
271                 return getRVI(rvi + "#" + suffix.substring(1, segmentEnd), suffix.substring(segmentEnd));\r
272             }\r
273             case '/': {\r
274                 int segmentEnd = getSegmentEnd(suffix);\r
275                 return getRVI(rvi + "/" + suffix.substring(1, segmentEnd), suffix.substring(segmentEnd));\r
276             }\r
277             default:\r
278                 return null;\r
279         }\r
280 \r
281     }\r
282 \r
283     public static Variable getRootVariable(ReadGraph graph) throws DatabaseException {\r
284         return graph.adapt(graph.getRootLibrary(), Variable.class);\r
285     }\r
286     \r
287     public static Resource getPossibleIndexRoot(ReadGraph graph, Variable variable) throws DatabaseException {\r
288         return graph.syncRequest(new PossibleVariableIndexRoot(variable));\r
289     }\r
290     \r
291     public static Resource getIndexRoot(ReadGraph graph, Variable variable) throws DatabaseException {\r
292         return graph.syncRequest(new VariableIndexRoot(variable));\r
293     }\r
294     \r
295     public static Resource getModel(ReadGraph graph, Variable variable) throws DatabaseException {\r
296         String URI = variable.getURI(graph);\r
297         return VariablesImpl.getFirst(graph, SimulationResource.getInstance(graph).Model, URI, 8);\r
298     }\r
299 \r
300     public static Resource getPossibleModel(ReadGraph graph, Variable variable) throws DatabaseException {\r
301         return graph.syncRequest(new PossibleVariableModel(variable));\r
302     }\r
303 \r
304     public static Resource getProject(ReadGraph graph, Variable variable) throws DatabaseException {\r
305         String URI = variable.getURI(graph);\r
306         return VariablesImpl.getFirst(graph, ProjectResource.getInstance(graph).Project, URI, 8);\r
307     }\r
308 \r
309     public static Variable getConfigurationContext(ReadGraph graph, Resource resource) throws DatabaseException {\r
310         SimulationResource SIMU = SimulationResource.getInstance(graph);\r
311         if(!graph.isInstanceOf(resource, SIMU.Model)) resource = graph.sync(new Model(resource));\r
312         Resource configurationResource = graph.getSingleObject(resource, SIMU.HasConfiguration);\r
313         return Variables.getVariable(graph, configurationResource);\r
314     }\r
315 \r
316     public static Resource getConfigurationContextResource(ReadGraph graph, Resource resource) throws DatabaseException {\r
317         Variable config = getConfigurationContext(graph, resource);\r
318         return config.getRepresents(graph);\r
319     }\r
320 \r
321     public static Variable getConfigurationContext(ReadGraph graph, Variable variable) throws DatabaseException {\r
322         SimulationResource SIMU = SimulationResource.getInstance(graph);\r
323         Resource model = Variables.getModel(graph, variable);\r
324         Resource configurationResource = graph.getSingleObject(model, SIMU.HasConfiguration);\r
325         return Variables.getVariable(graph, configurationResource);\r
326     }\r
327 \r
328     public static Resource getPossibleConfigurationContextResource(ReadGraph graph, Resource resource) throws DatabaseException {\r
329         Variable config = getPossibleConfigurationContext(graph, resource);\r
330         return config != null ? config.getPossibleRepresents(graph) : null;\r
331     }\r
332 \r
333     public static Variable getPossibleConfigurationContext(ReadGraph graph, Resource resource) throws DatabaseException {\r
334         SimulationResource SIMU = SimulationResource.getInstance(graph);\r
335         if (!graph.isInstanceOf(resource, SIMU.Model)) resource = graph.sync(new PossibleIndexRoot(resource));\r
336         if (resource == null)\r
337             return null;\r
338         Resource configurationResource = graph.getPossibleObject(resource, SIMU.HasConfiguration);\r
339         if (configurationResource == null)\r
340             return null;\r
341         return Variables.getPossibleVariable(graph, configurationResource);\r
342     }\r
343 \r
344     public static Variable getPossibleConfigurationContext(ReadGraph graph, Variable variable) throws DatabaseException {\r
345         SimulationResource SIMU = SimulationResource.getInstance(graph);\r
346         Resource model = getPossibleIndexRoot(graph, variable);\r
347         if (model == null)\r
348             return null;\r
349         Resource configurationResource = graph.getPossibleObject(model, SIMU.HasConfiguration);\r
350         if (configurationResource == null)\r
351             return null;\r
352         return Variables.getPossibleVariable(graph, configurationResource);\r
353     }\r
354 \r
355     public static Variable getConfigurationVariable(ReadGraph graph, Resource resource, String RVI) throws DatabaseException {\r
356         Variable context = getConfigurationContext(graph, resource);\r
357         return context.browse(graph, RVI);\r
358     }\r
359     \r
360     public static Variable getConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException {\r
361         Variable context = getConfigurationContext(graph, variable);\r
362         RVI rvi = variable.getRVI(graph);\r
363         return rvi.resolve(graph, context);\r
364     }\r
365 \r
366     public static Variable getPossibleConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException {\r
367         Variable context = getPossibleConfigurationContext(graph, variable);\r
368         if (context == null)\r
369             return null;\r
370         try {\r
371             RVI rvi = variable.getRVI(graph);\r
372             return rvi.resolvePossible(graph, context);\r
373         } catch (MissingVariableException e) {\r
374             // Ignore.\r
375             return null;\r
376         }\r
377     }\r
378 \r
379     public static Datatype getDatatype(ReadGraph graph, Resource resource, RVI rvi) throws DatabaseException {\r
380         Variable var = rvi.resolve(graph, getConfigurationContext(graph, resource));\r
381         return var.getDatatype(graph);\r
382     }\r
383 \r
384     @Deprecated\r
385     public static Resource getRealization(ReadGraph graph, Variable variable) throws DatabaseException {\r
386         String URI = variable.getURI(graph);\r
387         return VariablesImpl.getFirst(graph, Layer0X.getInstance(graph).Realization, URI, 8);\r
388     }\r
389 \r
390     public static boolean isContext(ReadGraph graph, Variable variable) throws DatabaseException {\r
391         Resource type = variable.getPossibleType(graph);\r
392         if(type != null) {\r
393             if(graph.isInheritedFrom(type, Layer0.getInstance(graph).RVIContext)) return true;\r
394         }\r
395         return false;\r
396     }\r
397 \r
398     public static Variable getPossibleContext(ReadGraph graph, Variable variable) throws DatabaseException {\r
399         if(isContext(graph, variable)) return variable;\r
400         Variable parent = variable.getParent(graph);\r
401         if(parent == null) return null;\r
402         return getPossibleContext(graph, parent);\r
403     }\r
404 \r
405     public static Variable getContext(ReadGraph graph, Variable variable) throws DatabaseException {\r
406         Variable context = getPossibleContext(graph, variable);\r
407         if(context == null) throw new DatabaseException("No context found for " + variable.getURI(graph));\r
408         else return context;\r
409     }\r
410 \r
411     public static RVI getRVI2(ReadGraph graph, Variable variable) throws DatabaseException {\r
412         return variable.getRVI(graph);\r
413     }\r
414 \r
415     public static RVI getPossibleRVI2(ReadGraph graph, Variable variable) throws DatabaseException {\r
416         try {\r
417             return variable.getRVI(graph);\r
418         } catch (DatabaseException e) {\r
419             return null;\r
420         }\r
421     }\r
422 \r
423     public static String getRVI(ReadGraph graph, Variable variable) throws DatabaseException {\r
424         Resource realizationResource = getRealization(graph, variable);\r
425         if (realizationResource == null)\r
426             throw new DatabaseException("No realization found for " + variable.getURI(graph));\r
427         return variable.getURI(graph).substring(graph.getURI(realizationResource).length()); \r
428     }\r
429 \r
430     public static String getRVI(ReadGraph graph, Resource config) throws DatabaseException {\r
431         Variable var = getVariable(graph, config);\r
432         return getRVI(graph, var);\r
433     }\r
434 \r
435     public static String getPossibleRVI(ReadGraph graph, Resource config) throws DatabaseException {\r
436         Variable var = getPossibleVariable(graph, config);\r
437         return var != null ? getPossibleRVI(graph, var) : null;\r
438     }\r
439 \r
440     public static String getPossibleRVI(ReadGraph graph, Variable variable) throws DatabaseException {\r
441         try {\r
442             return getRVI(graph, variable);\r
443         } catch (DatabaseException e) {\r
444             return null;\r
445         }\r
446     }\r
447 \r
448     public static List<Variable> getPath(ReadGraph graph, Variable base, Variable var) throws DatabaseException {\r
449         if(!isChild(graph, base, var)) return null;\r
450         LinkedList<Variable> result = new LinkedList<Variable>();\r
451         var = var.getParent(graph);\r
452         while(!var.equals(base)) {\r
453             result.addFirst(var);\r
454             var = var.getParent(graph);\r
455         }\r
456         return result;\r
457     }\r
458 \r
459     public static Variable getChild(ReadGraph graph, Variable base, Variable var) throws DatabaseException {\r
460         List<Variable> path = getPath(graph, base, var);\r
461         if(path == null || path.size() == 0) return null;\r
462         return path.get(0);\r
463     }\r
464 \r
465     public static boolean isChild(ReadGraph graph, Variable base, Variable var) throws DatabaseException {\r
466         if(base.equals(var)) return false;\r
467         return var.getURI(graph).startsWith(base.getURI(graph));\r
468     }\r
469 \r
470     public static Variable switchRealization(ReadGraph graph, Variable variable, Resource realization) throws DatabaseException {\r
471         Resource current = getRealization(graph, variable);\r
472         if(current == null) throw new DatabaseException("No current realization found for variable");\r
473         return switchRealization(graph, variable, current, realization);\r
474     }\r
475 \r
476     public static Variable switchPossibleContext(ReadGraph graph, Variable variable, Resource realization) throws DatabaseException {\r
477         Variable current = getPossibleContext(graph, variable);\r
478         if (current == null)\r
479             return null;\r
480         Resource currentContext = current.getPossibleRepresents(graph);\r
481         if (currentContext == null)\r
482             return null;\r
483         return switchPossibleRealization(graph, variable, currentContext, realization);\r
484     }\r
485 \r
486     public static Variable switchRealization(ReadGraph graph, Variable variable, Variable realization) throws DatabaseException {\r
487         Resource current = getRealization(graph, variable);\r
488         return switchRealization(graph, variable, current, realization);\r
489     }\r
490 \r
491     public static Variable switchRealization(ReadGraph graph, Variable variable, Resource currentRealization, Resource targetRealization) throws DatabaseException {\r
492         String currentURI = graph.getURI(currentRealization);\r
493         String targetURI = graph.getURI(targetRealization);\r
494         String variableURI = variable.getURI(graph);\r
495         String targetVariableURI = targetURI + variableURI.substring(currentURI.length());\r
496         return getVariable(graph, targetVariableURI);\r
497     }\r
498 \r
499     public static Variable switchRealization(ReadGraph graph, Variable variable, Resource currentRealization, Variable targetRealization) throws DatabaseException {\r
500         String currentURI = graph.getURI(currentRealization);\r
501         String targetURI = targetRealization.getURI(graph);\r
502         String variableURI = variable.getURI(graph);\r
503         String targetVariableURI = targetURI + variableURI.substring(currentURI.length());\r
504         return getVariable(graph, targetVariableURI);\r
505     }\r
506 \r
507     public static Variable switchPossibleRealization(ReadGraph graph, Variable variable, Resource currentRealization, Resource targetRealization) throws DatabaseException {\r
508         String currentURI = graph.getURI(currentRealization);\r
509         String targetURI = graph.getURI(targetRealization);\r
510         String variableURI = variable.getURI(graph);\r
511         String targetVariableURI = targetURI + variableURI.substring(currentURI.length());\r
512         return getPossibleVariable(graph, targetVariableURI);\r
513     }\r
514 \r
515     public static Variable toConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException {\r
516         Variable config = getConfigurationContext(graph, variable);\r
517         return switchRealization(graph, variable, config);\r
518     }\r
519 \r
520     public static Variable toPossibleConfigurationVariable(ReadGraph graph, Variable variable) throws DatabaseException {\r
521         \r
522         Resource represents = variable.getPossibleRepresents(graph);\r
523         if(represents == null) return null;\r
524         Resource config = getPossibleConfigurationContextResource(graph, represents);\r
525         if(config == null) return null;\r
526         return switchPossibleContext(graph, variable, config);\r
527 \r
528     }\r
529 \r
530     public static String toRVI(ReadGraph graph, List<Resource> compositePath) throws DatabaseException {\r
531         Layer0 L0 = Layer0.getInstance(graph);\r
532         StringBuilder rvi = new StringBuilder();\r
533         for (Resource composite : compositePath) {\r
534             String name = graph.getPossibleRelatedValue(composite, L0.HasName);\r
535             if (name == null)\r
536                 return null;\r
537 \r
538             rvi.append('/');\r
539             String escapedName = URIStringUtils.escape(name);\r
540             rvi.append(escapedName);\r
541         }\r
542         return rvi.toString();\r
543     }\r
544 \r
545     public static String appendRVI(ReadGraph graph, String modelURI, String rvi, Resource configuration) throws DatabaseException {\r
546 \r
547         Layer0 L0 = Layer0.getInstance(graph);\r
548         String partName = graph.getPossibleRelatedValue(configuration, L0.HasName);\r
549         if(partName == null) throw new MissingVariableException("Can not append a child corresponding to " + configuration + " to rvi '" + rvi + "' since there is no name.");\r
550         String escaped = URIStringUtils.escape(partName);\r
551         return rvi + "/" + escaped;\r
552 \r
553     }\r
554 \r
555     public static boolean isValid(ReadGraph graph, Variable variable) {\r
556         if(variable == null) return false;\r
557         try {\r
558             variable.getURI(graph);\r
559         } catch (DatabaseException e) {\r
560             return false;\r
561         }\r
562         return true;\r
563     }\r
564 \r
565     public static Variable possibleChildWithType(ReadGraph graph, Variable variable, Resource targetType) throws DatabaseException {\r
566         Variable found = null;\r
567         for(Variable child : variable.getChildren(graph)) {\r
568             Resource type = child.getPossiblePropertyValue(graph, Variables.TYPE);\r
569             if(type != null && graph.isInheritedFrom(type, targetType)) {\r
570                 if(found != null) return null;\r
571                 found = child;\r
572             }\r
573         }\r
574         return found;\r
575     }\r
576 \r
577     public static Collection<Variable> childrenWithType(ReadGraph graph, Variable variable, Resource targetType) throws DatabaseException {\r
578         ArrayList<Variable> result = new ArrayList<Variable>();\r
579         for(Variable child : variable.getChildren(graph)) {\r
580             Resource type = child.getPossiblePropertyValue(graph, Variables.TYPE);\r
581             if(graph.isInheritedFrom(type, targetType)) result.add(child);\r
582         }\r
583         return result;\r
584     }\r
585 \r
586     public static <T> T adapt(ReadGraph graph, Variable variable, String property, Class<T> clazz) throws DatabaseException {\r
587         Resource resource = variable.getPropertyValue(graph, property);\r
588         return graph.adapt(resource, clazz);\r
589     }\r
590 \r
591     public static <T> T getPossiblePropertyValue(RequestProcessor processor, Variable variable, Resource property, Binding binding) {\r
592         try {\r
593             return processor.sync(new TernaryRead<Variable,Resource,Binding,T>(variable, property, binding) {\r
594 \r
595                 @Override\r
596                 public T perform(ReadGraph graph) throws DatabaseException {\r
597                     return parameter.getPossiblePropertyValue(graph, parameter2, parameter3);\r
598                 }\r
599 \r
600             });\r
601         } catch (DatabaseException e) {\r
602             return null;\r
603         }\r
604     }\r
605 \r
606     public static Variable possibleActiveVariable(ReadGraph graph, Variable variable) throws DatabaseException {\r
607         Variable activeVariable = graph.sync(new PossibleActiveVariableFromVariable(variable));\r
608         return activeVariable;\r
609     }\r
610 \r
611     public static Variant requestNodeValue(ReadGraph graph, VariableNode<?> node) throws DatabaseException {\r
612         return requestNodeValue(graph, node, null);\r
613     }\r
614 \r
615     public static Variant requestNodeValue(ReadGraph graph, VariableNode<?> node, final Binding binding) throws DatabaseException {\r
616         Variant value = graph.syncRequest(new NodeValueRequest(node, binding));\r
617         if(PENDING_NODE_VALUE == value && graph.getSynchronous()) {\r
618                 // In this case a PENDING value was previously cached but now the value needs to be obtained for real.\r
619                 \r
620                         ValueGetter getter = new ValueGetter(node, binding);\r
621                         try {\r
622                                 node.support.manager.getRealm().syncExec(getter);\r
623                         } catch (InterruptedException e) {\r
624                                 Logger.defaultLogError(e);\r
625                         }\r
626                         \r
627                         if (getter.exception != null)\r
628                                 throw new DatabaseException(getter.exception);\r
629                         \r
630                         return getter.result;\r
631         }\r
632         return value; \r
633     }\r
634     \r
635     public static class NodeStructure {\r
636         // Immutable but wrapped with Collections.unmodifiableMap as an optimization\r
637         public final Map<String,Object> children;\r
638         // Immutable but not wrapped with Collections.unmodifiableMap as an optimization\r
639         public final Map<String,Object> properties;\r
640         private final int hash;\r
641 \r
642         public NodeStructure(Map<String, Object> children, Map<String, Object> properties) {\r
643             this.children = children;\r
644             this.properties = properties;\r
645             this.hash = calcHash();\r
646         }\r
647 \r
648         private int calcHash() {\r
649             return 31*children.hashCode() + 41*properties.hashCode();\r
650         }\r
651 \r
652         @Override\r
653         public int hashCode() {\r
654             return hash;\r
655         }\r
656 \r
657         @Override\r
658         public boolean equals(Object object) {\r
659             if (this == object)\r
660                 return true;\r
661             else if (object == null || object == Variables.PENDING_NODE_STRUCTURE)\r
662                 return false;\r
663             else if (!(object instanceof NodeStructure))\r
664                 return false;\r
665             NodeStructure r = (NodeStructure)object;\r
666             return r.children.equals(children) && r.properties.equals(properties);\r
667         }\r
668     }\r
669 \r
670     public static NodeStructure requestNodeStructure(ReadGraph graph, VariableNode<?> node) throws DatabaseException {\r
671         NodeStructure value = graph.syncRequest(new NodeStructureRequest(node));\r
672         if (value == null) throw new DatabaseException("External data access error");\r
673         if(PENDING_NODE_STRUCTURE == value && graph.getSynchronous()) {\r
674                 // In this case a PENDING value was previously cached but now the value needs to be obtained for real.\r
675                 \r
676                         StructureGetter getter = new StructureGetter(node);\r
677                         try {\r
678                                 node.support.manager.getRealm().syncExec(getter);\r
679                         } catch (InterruptedException e) {\r
680                                 Logger.defaultLogError(e);\r
681                                 throw new DatabaseException("External data access error", e);\r
682                         }\r
683                         \r
684                         if (getter.exception != null)\r
685                                 throw new DatabaseException("External data access error", getter.exception);\r
686                         if (getter.result == null)\r
687                                 throw new DatabaseException("External data access error");\r
688                         \r
689                         return getter.result;\r
690                 \r
691         }\r
692         return value; \r
693 \r
694     }\r
695     \r
696     public static String getPossibleUnit(ReadGraph graph, Variable variable) throws DatabaseException {\r
697         \r
698         try {\r
699                 \r
700                 Resource predicate = variable.getPossiblePredicateResource(graph);\r
701                 if(predicate != null) {\r
702                         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));\r
703                         if(info.definedUnit != null) return info.definedUnit;\r
704                 }\r
705                 \r
706                 Variant variant = variable.getVariantValue(graph);\r
707                 Binding binding = variant.getBinding();\r
708                 if(binding == null) return null;\r
709                 Datatype dt = binding.type();\r
710                 if(!(dt instanceof NumberType)) return null;\r
711                 NumberType nt = (NumberType)dt;\r
712                 return nt.getUnit();\r
713                 \r
714         } catch (DatabaseException e) {\r
715                 return null;\r
716         }\r
717         \r
718     }\r
719 \r
720     /**\r
721      * @param graph\r
722      * @param rvi\r
723      * @param context1 primary context to use for resolving the specified RVI, must not be null\r
724      * @param context2 secondary context to use for resolving the specified RVI, may be <code>null</code>\r
725      * @return pair of variables where first is the resolved variable and second\r
726      *         is the context it was resolved with\r
727      * @throws DatabaseException\r
728      * @since 1.18.1\r
729      */\r
730     public static Pair<Variable, Variable> resolvePossible(ReadGraph graph, RVI rvi, Variable context1, Variable context2) throws DatabaseException {\r
731         Variable v = rvi.resolvePossible(graph, context1);\r
732         if (v != null)\r
733             return new Pair<>(v, context1);\r
734         if (context2 != null) {\r
735             v = rvi.resolvePossible(graph, context2);\r
736             if (v != null)\r
737                 return new Pair<>(v, context2);\r
738         }\r
739         return null;\r
740     }\r
741 \r
742 \r
743     @SuppressWarnings("rawtypes")\r
744     private static class ValueGetter implements VariableNodeReadRunnable {\r
745 \r
746         final VariableNode n;\r
747         final Binding binding;\r
748         Variant result;\r
749         Exception exception;\r
750 \r
751         public ValueGetter(VariableNode n, Binding binding) {\r
752             this.n = n;\r
753             this.binding = binding;\r
754         }\r
755 \r
756         @SuppressWarnings("unchecked")\r
757         @Override\r
758         public void run() {\r
759             try {\r
760                 if (binding != null)\r
761                     result = new Variant(binding, n.support.manager.getValue(n.node, binding));\r
762                 else\r
763                     result = n.support.manager.getValue(n.node);\r
764             } catch (Exception e) {\r
765                 Logger.defaultLogError(e);\r
766                 exception = e;\r
767             }\r
768         }\r
769 \r
770     }\r
771 \r
772     @SuppressWarnings("rawtypes")\r
773     private static class StructureGetter implements VariableNodeReadRunnable {\r
774 \r
775         final VariableNode n;\r
776         NodeStructure result;\r
777         Exception exception;\r
778 \r
779         public StructureGetter(VariableNode n) {\r
780             this.n = n;\r
781         }\r
782 \r
783         @Override\r
784         public void run() {\r
785             try {\r
786                 result = NodeStructureRequest.get(n);\r
787             } catch (NodeManagerException e) {\r
788                 Logger.defaultLogError(e);\r
789                 exception = e;\r
790             }\r
791         }\r
792 \r
793     };\r
794 \r
795     public static Variable tryGetProperty(ReadGraph graph, Resource entity, Resource property) throws DatabaseException {\r
796         Variable v = Variables.getPossibleVariable(graph, entity);\r
797         return v != null ? v.getPossibleProperty(graph, property) : null;\r
798     }\r
799     \r
800         public static ValueAccessor createValueAccessor(Function1<Variable, Object> getValue1, Function2<Variable, Binding, Object> getValue2,\r
801                         Function2<Variable, Object, Object> setValue2, Function3<Variable, Object, Binding, Object> setValue3,\r
802                         Function1<Variable, Datatype> getDatatype) {\r
803                 return new SCLValueAccessor(getValue1, getValue2, setValue2, setValue3, getDatatype);\r
804         }\r
805 \r
806     \r
807 }\r