Document performance optimizations
[simantics/platform.git] / bundles / org.simantics.document.server / src / org / simantics / document / server / Functions.java
1 package org.simantics.document.server;
2
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.TreeMap;
12
13 import org.simantics.Simantics;
14 import org.simantics.databoard.Bindings;
15 import org.simantics.databoard.Datatypes;
16 import org.simantics.databoard.binding.Binding;
17 import org.simantics.databoard.type.Datatype;
18 import org.simantics.db.DirectStatements;
19 import org.simantics.db.ReadGraph;
20 import org.simantics.db.RequestProcessor;
21 import org.simantics.db.Resource;
22 import org.simantics.db.Session;
23 import org.simantics.db.Statement;
24 import org.simantics.db.WriteGraph;
25 import org.simantics.db.common.primitiverequest.Adapter;
26 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
27 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
28 import org.simantics.db.common.request.BinaryRead;
29 import org.simantics.db.common.request.ResourceRead;
30 import org.simantics.db.common.request.UniqueRead;
31 import org.simantics.db.common.request.WriteResultRequest;
32 import org.simantics.db.common.utils.Logger;
33 import org.simantics.db.common.utils.NameUtils;
34 import org.simantics.db.exception.DatabaseException;
35 import org.simantics.db.layer0.function.All;
36 import org.simantics.db.layer0.request.ProjectModels;
37 import org.simantics.db.layer0.request.PropertyInfo;
38 import org.simantics.db.layer0.request.PropertyInfoRequest;
39 import org.simantics.db.layer0.request.VariableProperty;
40 import org.simantics.db.layer0.request.VariableRead;
41 import org.simantics.db.layer0.request.VariableValueWithBinding;
42 import org.simantics.db.layer0.scl.SCLDatabaseException;
43 import org.simantics.db.layer0.variable.ConstantPropertyVariable;
44 import org.simantics.db.layer0.variable.ProxyChildVariable;
45 import org.simantics.db.layer0.variable.ProxySessionRequest;
46 import org.simantics.db.layer0.variable.ProxyVariableSupport;
47 import org.simantics.db.layer0.variable.ProxyVariables;
48 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
49 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
50 import org.simantics.db.layer0.variable.Variable;
51 import org.simantics.db.layer0.variable.VariableMap;
52 import org.simantics.db.layer0.variable.VariableMapImpl;
53 import org.simantics.db.layer0.variable.Variables;
54 import org.simantics.db.service.DirectQuerySupport;
55 import org.simantics.document.base.ontology.DocumentationResource;
56 import org.simantics.document.server.bean.Command;
57 import org.simantics.document.server.bean.DataDefinition;
58 import org.simantics.document.server.handler.AbstractEventHandler;
59 import org.simantics.document.server.handler.AbstractResponseHandler;
60 import org.simantics.document.server.handler.EventHandler;
61 import org.simantics.document.server.io.CommandContext;
62 import org.simantics.document.server.io.CommandContextImpl;
63 import org.simantics.document.server.io.CommandContextMutable;
64 import org.simantics.document.server.io.CommandResult;
65 import org.simantics.document.server.io.IConsole;
66 import org.simantics.document.server.request.NodeRequest;
67 import org.simantics.document.server.request.ServerSCLHandlerValueRequest;
68 import org.simantics.document.server.request.ServerSCLValueRequest;
69 import org.simantics.document.server.serverResponse.ServerResponse;
70 import org.simantics.document.server.serverResponse.SuccessResponse;
71 import org.simantics.document.server.state.StateNodeManager;
72 import org.simantics.document.server.state.StateRealm;
73 import org.simantics.document.server.state.StateSessionManager;
74 import org.simantics.modeling.ModelingResources;
75 import org.simantics.modeling.services.CaseInsensitiveComponentFunctionNamingStrategy;
76 import org.simantics.modeling.services.ComponentNamingStrategy;
77 import org.simantics.operation.Layer0X;
78 import org.simantics.project.IProject;
79 import org.simantics.scl.compiler.module.repository.ImportFailureException;
80 import org.simantics.scl.compiler.types.TCon;
81 import org.simantics.scl.compiler.types.Type;
82 import org.simantics.scl.compiler.types.Types;
83 import org.simantics.scl.reflection.annotations.SCLValue;
84 import org.simantics.scl.runtime.SCLContext;
85 import org.simantics.scl.runtime.function.Function;
86 import org.simantics.scl.runtime.function.Function1;
87 import org.simantics.scl.runtime.function.FunctionImpl1;
88 import org.simantics.scl.runtime.function.FunctionImpl4;
89 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
90 import org.simantics.scl.runtime.tuple.Tuple;
91 import org.simantics.scl.runtime.tuple.Tuple0;
92 import org.simantics.scl.runtime.tuple.Tuple2;
93 import org.simantics.scl.runtime.tuple.Tuple3;
94 import org.simantics.scl.runtime.tuple.Tuple4;
95 import org.simantics.scl.runtime.tuple.Tuple5;
96 import org.simantics.simulation.experiment.IExperiment;
97 import org.simantics.simulation.ontology.SimulationResource;
98 import org.simantics.simulation.project.IExperimentManager;
99 import org.simantics.structural2.variables.Connection;
100 import org.simantics.structural2.variables.StandardProceduralChildVariable;
101 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
102 import org.slf4j.LoggerFactory;
103
104 import gnu.trove.map.hash.THashMap;
105
106 public class Functions {
107
108     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Functions.class);
109     
110     @SCLValue(type = "VariableMap")
111     public static VariableMap primitiveProperties = new VariableMapImpl() {
112         private void storePropertyValueAndExceptions(ReadGraph graph, Variable parent, String name, Variable property, Map<String, Variable> map) {
113                 try {
114                         Object value = property.getValue(graph);
115                                 map.put(name, new ConstantPropertyVariable(parent, name, value, null));
116                 } catch (DatabaseException e) {
117                         Variable propertyExceptions = map.get(NodeRequest.PROPERTY_VALUE_EXCEPTIONS);
118                         Map<String, Exception> exceptionMap;
119                         if (propertyExceptions == null) {
120                                 exceptionMap = new TreeMap<String, Exception>();
121                                 propertyExceptions = new ConstantPropertyVariable(parent, NodeRequest.PROPERTY_VALUE_EXCEPTIONS, exceptionMap, null);
122                                 map.put(NodeRequest.PROPERTY_VALUE_EXCEPTIONS, propertyExceptions);
123                         } else {
124                                 try {
125                                                 exceptionMap = propertyExceptions.getValue(graph);
126                                         } catch (DatabaseException e1) {
127                                                 Logger.defaultLogError(e1);
128                                                 return;
129                                         }
130                         }
131                         String label = name;
132                         try {
133                                 label = property.getLabel(graph);
134                         } catch (DatabaseException e2) {
135
136                         }
137                         exceptionMap.put(label, e);
138                 }
139         }
140         
141         @Override
142         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
143             return All.getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
144         }
145
146         @Override
147         public Map<String, Variable> getVariables(final ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
148
149             if(map == null) map = new HashMap<String,Variable>();
150
151             Variable parent = context.getParent(graph);
152
153             DocumentationResource DOC = DocumentationResource.getInstance(graph);
154
155             if(parent instanceof StandardProceduralChildVariable) {
156
157                 StandardProceduralChildVariable procedural = (StandardProceduralChildVariable)parent;
158                 for(Variable property : procedural.getProperties(graph/*, DocumentationResource.URIs.Document_AttributeRelation*/)) {
159                     if(property instanceof StandardAssertedGraphPropertyVariable) {
160                         StandardAssertedGraphPropertyVariable ass = (StandardAssertedGraphPropertyVariable)property;
161                         if("dataDefinitions".equals(ass.property.name) || "commands".equals(ass.property.name)  || "pollingFunction".equals(ass.property.name)) {
162                                 storePropertyValueAndExceptions(graph, parent, ass.property.name, property, map);
163                         }
164                         continue;
165                     }
166                     Resource predicate = property.getPossiblePredicateResource(graph);
167                     if(predicate != null) {
168                         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
169                         if(info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
170                                 Variable prop = parent.getProperty(graph, predicate);
171                             storePropertyValueAndExceptions(graph, parent, info.name, prop, map);
172                         }
173                     }
174                 }
175
176             } else {
177
178                 Resource parentRes = parent.getRepresents(graph);
179                 {
180                         Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_commands);
181                         storePropertyValueAndExceptions(graph, parent, "commands", prop, map);
182                 }
183
184                 if (graph.getPossibleObject(parentRes, DOC.Properties_dataDefinitions) != null) {
185                         Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_dataDefinitions);
186                         storePropertyValueAndExceptions(graph, parent, "dataDefinitions", prop, map);
187                 }
188                 
189                 DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class);
190                 //PrimitivePropertyStatementsProcedure foo = new PrimitivePropertyStatementsProcedure();
191
192                 DirectStatements ds = dqs.getDirectPersistentStatements(graph, parentRes);
193
194                 for(Statement stm : ds) {
195                     Resource predicate = stm.getPredicate();
196                     PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
197
198                     if(info.isHasProperty && info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
199                         Variable prop = new StandardGraphPropertyVariable(graph, parent, predicate);
200                         storePropertyValueAndExceptions(graph, parent, info.name, prop, map);
201                     } else {
202                         Resource definition = graph.getPossibleObject(predicate, DOC.Document_definesAttributeRelation);
203                         if(definition != null) {
204                                 PropertyInfo info2 = graph.syncRequest(new PropertyInfoRequest(definition));
205                                 Variable prop = new StandardGraphPropertyVariable(graph, parent, definition);
206                             map.put(info2.name, new PrimitiveValueVariable(parent, info2.name, prop));
207                         }
208                     }
209                 }
210             }
211             return map;
212
213         }
214
215     };
216
217     static class DocumentPropertyKeys extends ResourceRead<List<String>> {
218
219         protected DocumentPropertyKeys(Resource resource) {
220             super(resource);
221         }
222
223         @Override
224         public List<String> perform(ReadGraph graph) throws DatabaseException {
225
226             List<String> result = new ArrayList<>();
227
228             DocumentationResource DOC = DocumentationResource.getInstance(graph);
229
230             if(graph.hasStatement(resource, DOC.Properties_commands))
231                 result.add("commands");
232             if(graph.hasStatement(resource, DOC.Properties_dataDefinitions))
233                 result.add("dataDefinitions");
234
235             DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class);
236             DirectStatements ds = dqs.getDirectPersistentStatements(graph, resource);
237
238             for(Statement stm : ds) {
239
240                 Resource predicate = stm.getPredicate();
241                 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
242
243                 if(info.isHasProperty && info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
244                     result.add(info.name);
245                 } else {
246                     Resource definition = graph.getPossibleObject(predicate, DOC.Document_definesAttributeRelation);
247                     if(definition != null) {
248                         PropertyInfo info2 = graph.syncRequest(new PropertyInfoRequest(definition));
249                         result.add(info2.name);
250                     }
251                 }
252             }
253
254             return result;
255
256         }
257
258     }
259
260     static class StandardDocumentProperties implements DocumentProperties {
261
262         @Override
263         public Collection<String> getKeys(ReadGraph graph, Variable parent) throws DatabaseException {
264
265             if(parent instanceof StandardProceduralChildVariable) {
266
267                 StandardProceduralChildVariable procedural = (StandardProceduralChildVariable)parent;
268                 List<String> result = new ArrayList<>();
269                 for(Variable property : procedural.getProperties(graph)) {
270                     if(property instanceof StandardAssertedGraphPropertyVariable) {
271                         StandardAssertedGraphPropertyVariable ass = (StandardAssertedGraphPropertyVariable)property;
272                         if("dataDefinitions".equals(ass.property.name) || "commands".equals(ass.property.name)  || "pollingFunction".equals(ass.property.name)) {
273                             result.add(ass.property.name);
274                         }
275                         continue;
276                     }
277                     Resource predicate = property.getPossiblePredicateResource(graph);
278                     if(predicate != null) {
279                         PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
280                         if(info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
281                             result.add(info.name);
282                         }
283                     }
284                 }
285
286                 return result;
287
288             } else {
289
290                 Resource parentRes = parent.getRepresents(graph);
291                 return graph.syncRequest(new DocumentPropertyKeys(parentRes), TransientCacheAsyncListener.instance());
292
293             }
294
295         }
296
297         @Override
298         public Object getValue(ReadGraph graph, Variable context, String key) throws DatabaseException {
299             return context.getPropertyValue(graph, key);
300         }
301
302     }
303     
304     public static DocumentProperties primitiveProperties() throws DatabaseException {
305         return new StandardDocumentProperties();
306     }
307     
308     @SCLValue(type = "VariableMap")
309     public static VariableMap inputSpaceChildren = new VariableMapImpl() {
310
311         private Variable getProxy(ReadGraph graph, Variable context) throws DatabaseException {
312             Variable root = Variables.getRootVariable(graph);
313             return new DocumentProxyChildVariable(context, context, root, ProxyChildVariable.CONTEXT_BEGIN);
314         }
315
316         @Override
317         public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
318
319             if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context);
320             return All.standardChildDomainChildren.getVariable(graph, context, name);
321
322         }
323
324         @Override
325         public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
326
327             map = All.standardChildDomainChildren.getVariables(graph, context, map);
328             if(map == null) map = new THashMap<String,Variable>();
329             map.put(ProxyChildVariable.CONTEXT_BEGIN, getProxy(graph, context));
330             return map;
331
332         }
333
334     };
335
336     static class DocumentProxyChildVariable extends ProxyChildVariable implements ProxyVariableSupport {
337
338         public DocumentProxyChildVariable(Variable base, Variable parent, Variable other, String name) {
339             super(base, parent, other, name);
340         }
341
342         @Override
343         public Variable create(Variable base, Variable parent, Variable other, String name) {
344             return new DocumentProxyChildVariable(base, parent, other, name);
345         }
346
347         public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
348
349                 if(CONTEXT_END.equals(name)) {
350                 if(other instanceof ProxyChildVariable) {
351                         // The context is also a proxy - let it do the job
352                     return super.getPossibleChild(graph, name);
353                 } else {
354                     return ProxyVariables.tryToOwnRenamed(graph, this, base, CONTEXT_END);
355                 }
356             }
357
358             return super.getPossibleChild(graph, name);
359
360         }
361
362         @Override
363         public Variable attachTo(ReadGraph graph, Variable parent) {
364             return attachToRenamed(graph, parent, name);
365         }
366         
367         @Override
368         public Variable attachToRenamed(ReadGraph graph, Variable parent, String name) {
369             if(this.parent.equals(base))
370                 return new DocumentProxyChildVariable(parent, parent, other, name);
371             else
372                 return new DocumentProxyChildVariable(base, parent, other, name);
373         }
374
375     }
376
377     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
378     public static Variable input(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
379         Variable session = graph.syncRequest(new ProxySessionRequest(context));
380         DocumentationResource DOC = DocumentationResource.getInstance(graph);
381         String uri = session.getPossiblePropertyValue(graph, DOC.Session_inputURI);
382         if(uri == null) {
383                 // TODO HAXX - Please fix this
384                 // we have no URI so this probably means that someone has inserted a non-session 
385                 // into the proxy variable => return that instead
386                 return session;
387         }
388         return Variables.getVariable(graph, uri);
389     }
390
391     public static Variable stateVariable(ReadGraph graph, Variable self) throws DatabaseException {
392         Variable session = graph.syncRequest(new ProxySessionRequest(self));
393         if (session == null)
394                 throw new DatabaseException("No state for " + self.getURI(graph));
395         return session.getPossibleChild(graph, "__scl__");
396     }
397
398     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
399     public static Variable state(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
400         Variable session = graph.syncRequest(new ProxySessionRequest(context));
401         if (session == null)
402             throw new DatabaseException("No state for " + context.getURI(graph));
403         return session.getPossibleChild(graph, "__scl__");
404     }
405
406     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
407     public static Variable icstate(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
408         Variable session = graph.syncRequest(new ProxySessionRequest(context));
409         return session.getPossibleChild(graph, "__icstate__");
410     }
411
412     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
413     public static Variable session(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
414         return graph.syncRequest(new ProxySessionRequest(context));
415     }
416
417     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
418     public static Variable experiment(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
419         // Try if experiment (run) has been used as the input
420         Variable var = input(graph, converter, context);
421         SimulationResource SR = SimulationResource.getInstance(graph);
422         while(var != null && !graph.isInstanceOf(var.getRepresents(graph), SR.Run)) {
423             var = var.getParent(graph);
424         }
425
426         if(var != null) {
427             IExperiment exp = getExperiment(graph, var);
428             if(exp == null)
429                 return null;
430         }
431
432         return var;
433     }
434
435     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
436     public static Variable model(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
437         Variable var = input(graph, converter, context);
438         ModelingResources MOD = ModelingResources.getInstance(graph);
439         while(var != null && !graph.isInstanceOf(var.getRepresents(graph), MOD.StructuralModel)) {
440             var = var.getParent(graph);
441         }
442
443         return var;
444     }
445
446     private static Collection<Variable> getBroadcasted(ReadGraph graph, Variable target) throws DatabaseException {
447
448         ArrayList<Variable> result = new ArrayList<Variable>();
449
450         DocumentationResource DOC = DocumentationResource.getInstance(graph);
451
452         Variable broadcasted = target.getPossibleProperty(graph, DOC.Relations_broadcasted);
453         if(broadcasted != null) result.add(broadcasted);
454
455         for(Variable child : DocumentServerUtils.getChildrenInOrdinalOrder(graph, target)) {
456                 result.addAll(getBroadcasted(graph, child));
457         }
458
459         return result;
460
461     }
462
463     private static List<Command> getCommands(ReadGraph graph, Collection<Variable> commandVariables, String trigger, CommandContext constants, boolean broadcast) throws DatabaseException {
464
465         if(commandVariables.isEmpty()) return Collections.emptyList();
466
467         String t = trigger;
468         TreeMap<Integer, List<Command>> sequences = new TreeMap<Integer, List<Command>>();
469
470         DocumentationResource DOC = DocumentationResource.getInstance(graph);
471
472         int count = 0;
473         for (Variable c : commandVariables) {
474
475             if(trigger == null)
476                 t = c.getName(graph);
477
478             Connection conn = c.getValue(graph);
479             Variable targetConnectionPoint = DocumentServerUtils.getPossibleCommandTriggerConnectionPoint(graph, c, conn);
480             if (targetConnectionPoint != null) {
481                 Variable target = targetConnectionPoint.getParent(graph);
482                 if (target != null) {
483
484                     Boolean enabled = target.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
485                     if(enabled != null && !enabled) continue;
486
487                     Integer ordinal;
488                     if (broadcast) {
489                         ordinal = ++count;
490                     } else {
491                         ordinal = 1;
492                             try {
493                                 String o = c.getPossiblePropertyValue(graph, "ordinal");
494                                 if(o != null)
495                                     ordinal = Integer.parseInt(o);
496                             } catch (NumberFormatException e) {}
497                     }
498
499                     String constantKey = target.getPossiblePropertyValue(graph, "constantKey");
500                     String constantValue = target.getPossiblePropertyValue(graph, "constantValue");
501
502                     CommandContextMutable newConstants = (CommandContextMutable)constants; 
503                     if(constantKey != null && constantValue != null) {
504                         if(!constantKey.isEmpty()) {
505                                 newConstants = new CommandContextImpl().merge(constants);
506                                 newConstants.putString(constantKey, constantValue);
507                         }
508                     }
509
510                     String requiredKey = target.getPossiblePropertyValue(graph, "requiredKey");
511                     if(requiredKey != null && !requiredKey.isEmpty()) {
512                         if (newConstants == constants) {
513                                 newConstants = new CommandContextImpl().merge(constants);
514                         }
515                                 newConstants.putRow(CommandContext.REQUIRED_KEYS, Collections.<Object>singletonList(requiredKey));
516                     }
517
518                     String forbiddenKey = target.getPossiblePropertyValue(graph, "forbiddenKey");
519                     if(forbiddenKey != null && !forbiddenKey.isEmpty()) {
520                         if (newConstants == constants) {
521                                 newConstants = new CommandContextImpl().merge(constants);
522                         }
523                                 newConstants.putRow(CommandContext.FORBIDDEN_KEYS, Collections.<Object>singletonList(forbiddenKey));
524                     }
525
526                     if(DOC.Relations_broadcast.equals(targetConnectionPoint.getPredicateResource(graph))) {
527
528                         // This is a broadcast terminal of a container
529                         List<Command> broadcastCommands = getCommands(graph, getBroadcasted(graph, target), t, newConstants, true);
530                         sequences.put(ordinal, broadcastCommands);
531
532                     } else {
533
534                         Command command = new Command(DocumentServerUtils.getId(graph, target), t, 
535                                         targetConnectionPoint.getName(graph), newConstants);
536                         sequences.put(ordinal, Collections.singletonList(command));
537
538                     }
539
540                 }
541             }
542         }
543
544         List<Command> commands = new ArrayList<Command>();
545         for (List<Command> commandList : sequences.values()) {
546                 for (Command command : commandList) {
547                         commands.add(command);
548                 }
549         }
550
551         return commands;
552     }
553
554     /**
555      * Commands
556      * 
557      * @param graph
558      * @param variable
559      * @return
560      * @throws DatabaseException
561      */
562     public static List<Command> commandList(ReadGraph graph, Variable variable) throws DatabaseException {
563         return getCommands(graph, DocumentServerUtils.getTriggerCommands(graph, variable.getParent(graph)), null, new CommandContextImpl(), false);
564     }
565
566     /**
567      * Data definitions
568      * 
569      * @param graph
570      * @param variable
571      * @return
572      * @throws DatabaseException
573      */
574     public static List<DataDefinition> dataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {
575         DocumentationResource DOC = DocumentationResource.getInstance(graph); 
576         ArrayList<DataDefinition> dataDefinitions = new ArrayList<DataDefinition>();
577         // Find data definition connections
578         for (Variable dataDefinitionRelation : DocumentServerUtils.getDataDefinitions(graph, variable.getParent(graph))) {
579             Connection dataDefinitionConnection = dataDefinitionRelation.getValue(graph);
580             // Find data the other end of definition connection
581             Collection<Variable> dataDefinitionProviders = DocumentServerUtils.getPossibleOtherConnectionPoints(graph,
582                     dataDefinitionRelation, dataDefinitionConnection);
583             if (dataDefinitionProviders != null) {
584
585                 for(Variable dataDefinitionProvider : dataDefinitionProviders) {
586
587                     Variable dataDefinition = dataDefinitionProvider.getParent(graph);
588                     if (dataDefinition != null) {
589                         // Found other end. Is should contain ONE data
590 // definition connection to the actual data
591                         Collection<Variable> dataCollection = DocumentServerUtils.getDataRelations(graph, dataDefinition);
592                         if (dataCollection.size() == 1) {
593                             Variable dataRelation = dataCollection.iterator().next();
594                             Connection dataConnection = dataRelation.getValue(graph);
595                             // Find data the other end of definition connection
596                             Variable dataConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph,
597                                     dataRelation, dataConnection);
598                             if (dataConnectionPoint != null) {
599                                 Variable data = dataConnectionPoint.getParent(graph);
600                                 Resource type = dataDefinition.getPossibleType(graph, DOC.Components_Component);
601
602                                 if (graph.isInheritedFrom(type, DOC.Components_DefVar)) {
603
604                                         String sourceProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_source,
605                                                 Bindings.STRING);
606                                         String targetProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_target,
607                                                 Bindings.STRING);
608
609                                         dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
610                                                         sourceProperty, targetProperty));
611
612                                 } else if (graph.isInheritedFrom(type, DOC.Components_DefVars)) {
613
614                                         List<String> sourcesProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_sources), String.class);
615                                         List<String> targetsProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_targets), String.class);
616
617                                         for (int i = 0; i < Math.min(sourcesProperty.size(), targetsProperty.size()); i++) {
618                                                 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
619                                                         sourcesProperty.get(i), targetsProperty.get(i)));
620                                         }
621                                 }
622                             }
623                         }
624                     }
625                 }
626             }
627         }
628         return dataDefinitions;
629     }
630
631     @SuppressWarnings("unchecked")
632         private static <T> List<T> toList(Object o, Class<T> c) {
633         List<T> result = null;
634         if (o instanceof List) {
635                 return (List<T>)o;
636         } else if (o instanceof Object[]) {
637                 result = new ArrayList<T>(((Object[])o).length);
638                 for (T item : (T[])o) {
639                         result.add(item);
640                 }
641                 return result;
642         } else {
643                 return Collections.<T>emptyList();
644         }
645     }
646
647     @Deprecated
648     public static AbstractEventHandler emptyOnClick(ReadGraph graph) throws DatabaseException {
649         return new EventHandler() {
650             @Override
651             public ServerResponse handle(ReadGraph graph, CommandContext parameters) throws DatabaseException {
652                 return null;
653             }
654         };
655     }
656
657     @Deprecated
658     public static AbstractEventHandler writeEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
659
660         final Session session = graph.getSession();
661
662         return new AbstractEventHandler() {
663
664                         @Override
665                         public CommandResult handle(final CommandContext parameters) {
666
667                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
668
669                 try {
670
671                                         String result = session.sync(new WriteResultRequest<String>() {
672
673                                             @Override
674                                             public String perform(WriteGraph graph) throws DatabaseException {
675                                                 SCLContext sclContext = SCLContext.getCurrent();
676                                                 Object oldGraph = sclContext.put("graph", graph);
677                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
678                                                 try {
679                                                     Function1<String,String> pf = new FunctionImpl1<String,String>() {
680                                                         @Override
681                                                         public String apply(String key) {
682                                                             return parameters.getString(key);
683                                                         }
684                                                     }; 
685                                                     Object response = (String)fn.apply(variable, pf);
686                                                     if(response instanceof String) {
687                                                         return (String)response;
688                                                     }
689                                                     return null;
690                                                 } finally {
691                                                         sclContext.put("graph", oldGraph);
692                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
693                                                 }
694
695                                             }
696
697                                         });
698
699                         return new SuccessResponse(result);
700
701                                 } catch (Throwable e) {
702                                         Logger.defaultLogError(e);
703                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
704                                 }
705
706                         }
707
708         };
709     }
710
711     @Deprecated
712     public static AbstractEventHandler readEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
713
714         final Session session = graph.getSession();
715
716         return new AbstractEventHandler() {
717
718                         @Override
719                         public CommandResult handle(final CommandContext parameters) {
720
721                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
722
723                 try {
724
725                                         String result = session.sync(new UniqueRead<String>() {
726
727                                             @Override
728                                             public String perform(ReadGraph graph) throws DatabaseException {
729                                                 SCLContext sclContext = SCLContext.getCurrent();
730                                                 Object oldGraph = sclContext.put("graph", graph);
731                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
732                                                 try {
733                                                     Function1<String,String> pf = new FunctionImpl1<String,String>() {
734                                                         @Override
735                                                         public String apply(String key) {
736                                                             return parameters.getString(key);
737                                                         }
738                                                     }; 
739                                                     Object response = (String)fn.apply(variable, pf);
740                                                     if(response instanceof String) {
741                                                         return (String)response;
742                                                     }
743                                                     return null;
744                                                 } finally {
745                                                         sclContext.put("graph", oldGraph);
746                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
747                                                 }
748
749                                             }
750
751                                         });
752
753                         return new SuccessResponse(result);
754
755                                 } catch (Throwable e) {
756                                         Logger.defaultLogError(e);
757                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
758                                 }
759
760                         }
761
762         };
763     }
764
765     @Deprecated
766     public static AbstractEventHandler readEventHandler2(ReadGraph graph, final Function fn) {
767
768         final Session session = graph.getSession();
769
770         return new AbstractEventHandler() {
771
772                         @Override
773                         public CommandResult handle(final CommandContext parameters) {
774
775                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
776
777                 try {
778
779                         CommandResult result = session.sync(new UniqueRead<CommandResult>() {
780
781                                             @Override
782                                             public CommandResult perform(ReadGraph graph) throws DatabaseException {
783                                                 SCLContext sclContext = SCLContext.getCurrent();
784                                                 Object oldGraph = sclContext.put("graph", graph);
785                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
786                                                 try {
787                                                     Object response = fn.apply(parameters);
788                                                     if(response instanceof CommandResult) {
789                                                         return (CommandResult)response;
790                                                     }
791                                                     return null;
792                                                 } finally {
793                                                         sclContext.put("graph", oldGraph);
794                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
795                                                 }
796
797                                             }
798
799                                         });
800
801                         return result;
802
803                                 } catch (Throwable e) {
804                                         Logger.defaultLogError(e);
805                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
806                                 }
807
808                         }
809
810         };
811     }
812
813     public static AbstractEventHandler responseHandler(ReadGraph graph, Variable self, String function) throws DatabaseException {
814
815         Variable anyFunction = self.browse(graph, ".#" + function);
816         if(anyFunction == null) return null;
817
818         final List<TCon> effects = ServerSCLHandlerValueRequest.getEffects(graph, anyFunction);
819
820         Function1<CommandContext, CommandResult> fn = anyFunction.getValue(graph);
821         //String expression = anyFunction.getPropertyValue(graph, "expression");
822
823         final Session session = graph.getSession();
824
825         return new AbstractResponseHandler(fn) {
826
827                 private String formatError(RequestProcessor proc, Throwable t) {
828
829                         try {
830
831                                         return proc.syncRequest(new UniqueRead<String>() {
832
833                                                 @Override
834                                                 public String perform(ReadGraph graph) throws DatabaseException {
835                                                         Variable proxy = ProxyVariables.proxyVariableRoot(graph, anyFunction);
836                                                         String uri2 = proxy.getURI(graph);
837                                                         String uri = self.getParent(graph).getURI(graph);
838
839                                                         String path = uri.substring(uri2.length());
840
841                                                         String expr = anyFunction.getPossiblePropertyValue(graph, "expression");
842                                                         StringBuilder message = new StringBuilder();
843                                                         message.append("Handler execution failed\n");
844                                                         message.append(" handler=" + path + "\n");
845                                                         message.append(" expression=" + expr + "\n");
846                                                         message.append(" message=" + t.getMessage() + "\n");
847
848                                                         StringWriter sw = new StringWriter();
849                                                         t.printStackTrace(new PrintWriter(sw));
850                                                         message.append(" stack trace=" + sw);
851
852                                                         return message.toString();
853                                                 }
854
855                                         });
856
857                                 } catch (DatabaseException e) {
858
859                                         return e.getMessage();
860
861                                 }
862
863                 }
864
865                         @Override
866                         public CommandResult handle(final CommandContext parameters) {
867
868                                 IConsole console = parameters.getValue("__console__");
869                                 SCLReportingHandler printer = (console != null) ? new ConsoleSCLReportingHandler(console)
870                                                 : (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
871
872                 try {
873
874                         Object result = null;
875                         if(effects.contains(Types.WRITE_GRAPH)) {
876
877                                 result = session.syncRequest(new WriteResultRequest<Object>() {
878
879                                                         @Override
880                                                         public Object perform(WriteGraph graph)
881                                                                         throws DatabaseException {
882                                                 SCLContext sclContext = SCLContext.getCurrent();
883                                                 Object oldGraph = sclContext.put("graph", graph);
884                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
885                                                 try {
886                                                         return fn.apply(parameters);
887                                                 } finally {
888                                                         sclContext.put("graph", oldGraph);
889                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
890                                                 }
891
892                                                         }
893                                 });
894
895                         } else if(effects.contains(Types.READ_GRAPH)) {
896
897                                 result = session.sync(new UniqueRead<Object>() {
898
899                                         @Override
900                                         public Object perform(ReadGraph graph) throws DatabaseException {
901
902                                                 SCLContext sclContext = SCLContext.getCurrent();
903                                                 Object oldGraph = sclContext.put("graph", graph);
904                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
905
906                                                 try {
907                                                         return fn.apply(parameters);
908                                                 } finally {
909                                                         sclContext.put("graph", oldGraph);
910                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
911                                                 }
912
913                                         }
914                                 });
915
916                         } else {
917
918                                                 SCLContext sclContext = SCLContext.getCurrent();
919                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
920                                                 try {
921                                                         result = fn.apply(parameters);
922                                                 } finally {
923                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
924                                                 }
925
926                         }
927
928                         if (result instanceof org.simantics.document.server.serverResponse.Error) {
929                                 return (CommandResult)result;
930                         }
931
932                         if (result instanceof CommandResult) {
933                                 return (CommandResult)result;
934                         } else {
935                                 CommandContextMutable assignments = new CommandContextImpl();
936                                 assignments.putValue("result", result);
937                                 return new ServerResponse(200, "", assignments);
938                         }
939
940                                 } catch (Throwable e) {
941                                         return new org.simantics.document.server.serverResponse.Error(formatError(Simantics.getSession(), e));
942                                 }
943
944                         }
945
946         };
947     }
948
949     @Deprecated
950     public static AbstractEventHandler writeEventHandler2(ReadGraph graph, final Function fn) {
951
952         final Session session = graph.getSession();
953
954         return new AbstractEventHandler() {
955
956                         @Override
957                         public CommandResult handle(final CommandContext parameters) {
958
959                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
960
961                 try {
962
963                         CommandResult result = session.syncRequest(new WriteResultRequest<CommandResult>() {
964
965                                             @Override
966                                             public CommandResult perform(WriteGraph graph) throws DatabaseException {
967                                                 SCLContext sclContext = SCLContext.getCurrent();
968                                                 Object oldGraph = sclContext.put("graph", graph);
969                                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
970                                                 try {
971                                                     Object response = fn.apply(parameters);
972                                                     if(response instanceof CommandResult) {
973                                                         return (CommandResult)response;
974                                                     }
975                                                     return null;
976                                                 } finally {
977                                                         sclContext.put("graph", oldGraph);
978                                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
979                                                 }
980
981                                             }
982
983                                         });
984
985                         return result;
986
987                                 } catch (Throwable e) {
988                                         Logger.defaultLogError(e);
989                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
990                                 }
991
992                         }
993
994         };
995     }
996
997
998     @Deprecated
999     public static AbstractEventHandler eventHandler2(ReadGraph graph, final Function fn) {
1000
1001         return new AbstractEventHandler() {
1002
1003                         @Override
1004                         public CommandResult handle(final CommandContext parameters) {
1005
1006                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
1007
1008                 try {
1009
1010                         SCLContext sclContext = SCLContext.getCurrent();
1011                         Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
1012                         try {
1013                                 Object response = fn.apply(parameters);
1014                                 if(response instanceof CommandResult) {
1015                                         return (CommandResult)response;
1016                                 }
1017                                 return null;
1018                         } finally {
1019                                 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1020                         }
1021
1022                                 } catch (Throwable e) {
1023                                         Logger.defaultLogError(e);
1024                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
1025                                 }
1026
1027                         }
1028
1029         };
1030     }
1031
1032     @Deprecated
1033     public static AbstractEventHandler eventHandler(ReadGraph graph, final Function fn) {
1034
1035         return new AbstractEventHandler() {
1036
1037                         @Override
1038                         public CommandResult handle(final CommandContext parameters) {
1039
1040                 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
1041
1042                 try {
1043
1044                         String result = "";
1045
1046                                 SCLContext sclContext = SCLContext.getCurrent();
1047                                 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
1048                                 try {
1049                                     Function1<String,String> pf = new FunctionImpl1<String,String>() {
1050                                         @Override
1051                                         public String apply(String key) {
1052                                             return parameters.getString(key);
1053                                         }
1054                                     }; 
1055                                     Object response = (String)fn.apply(pf);
1056                                     if(response instanceof String) {
1057                                         result = (String)response;
1058                                     }
1059                                 } finally {
1060                                         sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1061                                 }
1062
1063                         return new SuccessResponse(result);
1064
1065                                 } catch (Throwable e) {
1066                                         Logger.defaultLogError(e);
1067                                         return new org.simantics.document.server.serverResponse.Error(e.getMessage()); 
1068                                 }
1069
1070                         }
1071
1072         };
1073     }
1074
1075     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1076     public static Object sclValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1077         return ServerSCLValueRequest.compileAndEvaluate(graph, context);
1078     }
1079
1080     @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1081     public static Object sclHandlerValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1082         return ServerSCLHandlerValueRequest.compileAndEvaluate(graph, context);
1083     }
1084
1085     @SCLValue(type = "ReadGraph -> Resource -> Resource -> ComponentNamingStrategy")
1086     public static ComponentNamingStrategy componentNamingStrategy(ReadGraph graph, Resource converter, Resource context) throws DatabaseException {
1087         return createComponentNamingStrategy(graph);
1088     }
1089
1090     public static CaseInsensitiveComponentFunctionNamingStrategy createComponentNamingStrategy(ReadGraph graph) throws DatabaseException {
1091         Layer0X L0X = Layer0X.getInstance(graph);
1092         @SuppressWarnings({ "unchecked", "rawtypes" })
1093         final Function dependencies = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());
1094         @SuppressWarnings("rawtypes")
1095         Function moduleNameFunction = new FunctionImpl4<ReadGraph, Resource, String, Integer, List<Map<String, Object>>>() {
1096             @Override
1097             public Object apply(ReadGraph p0, Resource p1, String p2) {
1098                 return apply(p0, p1, p2);
1099             }
1100             @SuppressWarnings("unchecked")
1101             @Override
1102             public List<Map<String, Object>> apply(ReadGraph graph, Resource model, String search, Integer maxResults) {
1103                 return (List<Map<String, Object>>)dependencies.apply(graph, model, search, maxResults);
1104             }
1105         };
1106         return new CaseInsensitiveComponentFunctionNamingStrategy("%s%02d", moduleNameFunction);
1107     }
1108
1109     public static IExperiment getExperiment(ReadGraph graph, Variable variable) throws DatabaseException {
1110         if (variable == null)
1111             return null;
1112
1113         SimulationResource SIMU = SimulationResource.getInstance(graph);
1114
1115         Variable var = variable;
1116         Resource represents = var.getRepresents(graph);
1117         Resource activeRun = null;
1118         if (represents != null && graph.isInstanceOf(represents, SIMU.Run)) {
1119             activeRun = represents;
1120         }
1121
1122         IProject project = Simantics.peekProject();
1123         if (activeRun != null && project != null) {
1124             IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
1125             if (expMan != null)
1126                 return expMan.getExperiment(NameUtils.getSafeName(graph, activeRun));
1127         }
1128
1129         return null;
1130     }
1131
1132     public static CommandContextMutable putTuple(CommandContextMutable context, String key, Object tuple) {
1133         List<Object> list = new ArrayList<Object>();
1134         if (tuple instanceof Tuple) {
1135                 Collections.addAll(list, ((Tuple)tuple).toArray());
1136         } else {
1137                 list.add(tuple);
1138         }
1139         context.putRow(key, list);
1140         return context;
1141     }
1142
1143     public static List<Object> getTuples(CommandContext context, String key) {
1144         List<List<Object>> rows = context.getRows(key);
1145         List<Object> tuples = new ArrayList<Object>();
1146         if (rows != null) {
1147                 for (List<Object> row : rows) {
1148                         switch (row.size()) {
1149                         case 0: tuples.add(Tuple0.INSTANCE); break;
1150                         case 1: tuples.add(row.get(1)); break;
1151                         case 2: tuples.add(new Tuple2(row.get(0), row.get(1))); break;
1152                         case 3: tuples.add(new Tuple3(row.get(0), row.get(1), row.get(2))); break;
1153                         case 4: tuples.add(new Tuple4(row.get(0), row.get(1), row.get(2), row.get(3))); break;
1154                         case 5: tuples.add(new Tuple5(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4))); break;
1155                         }
1156                 }
1157         }
1158         return tuples;
1159     }
1160
1161     public static String printContext(CommandContext context) {
1162         return context.toString();
1163     }
1164
1165     @SCLValue(type = "AbstractEventHandler")
1166     public static AbstractEventHandler emptyEvent = new AbstractEventHandler() {
1167
1168                 @Override
1169                 public CommandResult handle(CommandContext context) {
1170                         return null;
1171                 }
1172
1173     };
1174
1175     public static String sclStateKey(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1176
1177         String baseURI = base.getURI(graph);
1178
1179         String selfURI = self.getURI(graph);
1180
1181         String prefix = selfURI.substring(0, selfURI.indexOf(ProxyChildVariable.CONTEXT_BEGIN));
1182         String suffix = selfURI.substring(selfURI.lastIndexOf(ProxyChildVariable.CONTEXT_END) + ProxyChildVariable.CONTEXT_END.length());
1183         String stripped = prefix + suffix;
1184
1185         String relative = Variables.getRelativeRVI(baseURI, stripped); 
1186
1187         return Variables.getRVI(relative, ref);
1188
1189     }
1190
1191     public static Variable sclStateVariable(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1192
1193         String id = sclStateKey(graph, base, self, ref);
1194
1195         Variable sclVar = base.getPossibleChild(graph, "__scl__");
1196         if(sclVar == null) return null;
1197
1198         return sclVar.getPossibleProperty(graph, id);
1199
1200     }
1201
1202     public static Object sclStateValueOrDefault(ReadGraph graph, Variable base, Variable self, String ref, Object defaultValue) throws DatabaseException {
1203
1204         Variable stateVariable = sclStateVariable(graph, base, self, ref);
1205         if (stateVariable != null) {
1206
1207                 return stateVariable.getValue(graph);
1208
1209         } else {
1210
1211                 return defaultValue;
1212
1213         }
1214     }
1215
1216     public static void setSclStateValue(WriteGraph graph, Variable base, Variable self, String ref, Object value) throws DatabaseException {
1217
1218         String id = sclStateKey(graph, base, self, ref);
1219
1220                 StateRealm realm = (StateRealm) StateSessionManager.getInstance().getOrCreateRealm(graph, base.getURI(graph)+"/__scl__");
1221                 StateNodeManager nodeManager = (StateNodeManager) realm.getNodeManager();
1222                 nodeManager.setState(id, value);
1223
1224     }
1225
1226     public static Object projectComponentState(ReadGraph graph, Variable self, String ref, Object defaultValue) throws DatabaseException {
1227         Resource project = Simantics.getProjectResource();
1228         Variable component = self.getParent(graph);
1229         Variable projectVariable = Variables.getVariable(graph, project);
1230         return sclStateValueOrDefault(graph, projectVariable, component, ref, defaultValue);
1231     }
1232
1233     public static void setProjectComponentState(WriteGraph graph, Variable self, String ref, Object value) throws DatabaseException {
1234         Resource project = Simantics.getProjectResource();
1235         Variable component = self.getParent(graph);
1236         Variable projectVariable = Variables.getVariable(graph, project);
1237         setSclStateValue(graph, projectVariable, component, ref, value);
1238     }
1239
1240     private static Type getSCLType(Object value) throws DatabaseException {
1241         Binding b = Bindings.getBindingUnchecked(value.getClass());
1242         Datatype t = b.type();
1243         if(Datatypes.STRING.equals(t)) return Types.STRING;
1244         if(Datatypes.DOUBLE.equals(t)) return Types.DOUBLE;
1245         throw new DatabaseException("Type not supported");
1246     }
1247
1248     public static List<Variable> documentModelContribution(ReadGraph graph, Resource doc) throws DatabaseException {
1249         Resource project = Simantics.getProjectResource();
1250         ArrayList<Variable> result = new ArrayList<Variable>();
1251         for(Resource model : graph.syncRequest(new ProjectModels(project))) {
1252                 result.add(Variables.getVariable(graph, model));
1253         }
1254         return result;
1255     }
1256
1257     public static String documentModelContributionLabel(ReadGraph graph, Variable var) throws DatabaseException {
1258         return var.getName(graph);
1259     }
1260
1261     public static Object getPropertyValueCached(ReadGraph graph, Variable variable, String name, Binding binding) throws DatabaseException {
1262         Variable property = graph.syncRequest(new VariableProperty(variable, name));
1263         return graph.syncRequest(new VariableValueWithBinding<Object>(property, binding));
1264     }
1265
1266     public static class ParentExistsRequest extends VariableRead<Boolean> {
1267
1268                 public ParentExistsRequest(Variable parent) {
1269                         super(parent);
1270                 }
1271
1272                 @Override
1273                 public Boolean perform(ReadGraph graph) throws DatabaseException {
1274                         
1275                         Variable existsProperty = variable.getPossibleProperty(graph, "exists");
1276                         if(existsProperty == null) return true;
1277                         
1278                         Boolean exists = existsProperty.getPossibleValue(graph, Bindings.BOOLEAN);
1279                         if (exists == null || !exists) return false;
1280
1281                 return graph.syncRequest(new ParentExistsRequest(variable.getParent(graph)));
1282
1283                 }
1284
1285     } 
1286
1287     public static class PathExistsRequest extends VariableRead<Boolean> {
1288
1289                 public PathExistsRequest(Variable variable) {
1290                         super(variable);
1291                 }
1292
1293                 @Override
1294                 public Boolean perform(ReadGraph graph) throws DatabaseException {
1295
1296                         Variable widget = variable.getParent(graph);
1297
1298                 Boolean exists = widget.getPossiblePropertyValue(graph, "exists");
1299                         if (exists == null || !exists) return false;
1300
1301                 if (!graph.syncRequest(new ParentExistsRequest(widget.getParent(graph)))) return false;
1302
1303                 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1304                 Collection <Variable> cps = widget.getProperties(graph, DocumentationResource.URIs.Relations_parentRelation);
1305                 for (Variable cp : cps) {
1306
1307                         Connection conn = cp.getValue(graph);
1308                                 Variable otherCp = DocumentServerUtils.getPossibleChildConnectionPoint(graph, cp, conn);
1309                                 if (otherCp != null) {
1310                                         Variable parentWidget = otherCp.getParent(graph);
1311                                         if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1312                                                 return true;
1313                                         }
1314                                 } else {
1315                                         Variable parentCp = graph.sync(new BinaryRead<Variable, Connection, Variable>(widget, conn) {
1316                                     @Override
1317                                     public Variable perform(ReadGraph graph) throws DatabaseException {
1318                                         DocumentationResource DOC = DocumentationResource.getInstance(graph);
1319                                         Collection<VariableConnectionPointDescriptor> descs = parameter2.getConnection2().getConnectionPointDescriptors(graph, parameter, null);
1320
1321                                                 for(VariableConnectionPointDescriptor desc : descs) {
1322                                                         if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
1323                                                                 return desc.getVariable(graph);
1324                                                         }
1325                                                 }
1326                                                 return null;
1327                                     }
1328                                 });
1329                                         if (parentCp != null) {
1330                                                 Variable parentWidget = parentCp.getParent(graph);
1331                                                 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1332                                                         return true;
1333                                                 }
1334                                         }
1335                                 }
1336                         }
1337
1338                         Resource type = widget.getType(graph);
1339                         return graph.isInheritedFrom(type, DOC.Components_ParentlessComponent) ||
1340                                 (graph.isInheritedFrom(type, DOC.DocumentComponent) && cps.isEmpty());
1341                 }
1342     }
1343
1344     @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1345     public static boolean pathExists(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1346         return graph.syncRequest(new PathExistsRequest(context));
1347     }
1348
1349     public static String compileDocumentSCLValueExpression(ReadGraph graph, Variable context) {
1350         try {
1351             ServerSCLValueRequest.validate(graph, context);
1352             return "";
1353         } catch (Exception e) {
1354             return resolveIssueMessage(e);
1355         }
1356     }
1357     
1358     private static String resolveIssueMessage(Exception e) {
1359         if (e instanceof ImportFailureException)
1360             return "";
1361         if (e.getCause() != null && e.getCause() instanceof ImportFailureException)
1362             return "";
1363         if (e instanceof SCLDatabaseException) {
1364             SCLDatabaseException ee = (SCLDatabaseException) e;
1365             return ee.getMessage();
1366         }
1367         if (LOGGER.isDebugEnabled())
1368             LOGGER.debug("", e);
1369         return e.getMessage();
1370     }
1371
1372 }