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