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