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