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