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