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