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