1 package org.simantics.document.server;
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;
10 import java.util.TreeMap;
12 import org.simantics.Simantics;
13 import org.simantics.databoard.Bindings;
14 import org.simantics.databoard.Datatypes;
15 import org.simantics.databoard.binding.Binding;
16 import org.simantics.databoard.type.Datatype;
17 import org.simantics.db.ReadGraph;
18 import org.simantics.db.RequestProcessor;
19 import org.simantics.db.Resource;
20 import org.simantics.db.Session;
21 import org.simantics.db.WriteGraph;
22 import org.simantics.db.common.primitiverequest.Adapter;
23 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
24 import org.simantics.db.common.request.UnaryRead;
25 import org.simantics.db.common.request.UniqueRead;
26 import org.simantics.db.common.request.WriteResultRequest;
27 import org.simantics.db.common.utils.Logger;
28 import org.simantics.db.common.utils.NameUtils;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.function.All;
31 import org.simantics.db.layer0.request.ProjectModels;
32 import org.simantics.db.layer0.request.VariableProperty;
33 import org.simantics.db.layer0.request.VariableRead;
34 import org.simantics.db.layer0.request.VariableValueWithBinding;
35 import org.simantics.db.layer0.variable.ConstantPropertyVariable;
36 import org.simantics.db.layer0.variable.ProxyChildVariable;
37 import org.simantics.db.layer0.variable.ProxySessionRequest;
38 import org.simantics.db.layer0.variable.ProxyVariables;
39 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
40 import org.simantics.db.layer0.variable.Variable;
41 import org.simantics.db.layer0.variable.VariableMap;
42 import org.simantics.db.layer0.variable.VariableMapImpl;
43 import org.simantics.db.layer0.variable.Variables;
44 import org.simantics.document.base.ontology.DocumentationResource;
45 import org.simantics.document.server.bean.Command;
46 import org.simantics.document.server.bean.DataDefinition;
47 import org.simantics.document.server.handler.AbstractEventHandler;
48 import org.simantics.document.server.handler.AbstractResponseHandler;
49 import org.simantics.document.server.handler.EventHandler;
50 import org.simantics.document.server.io.CommandContext;
51 import org.simantics.document.server.io.CommandContextImpl;
52 import org.simantics.document.server.io.CommandContextMutable;
53 import org.simantics.document.server.io.CommandResult;
54 import org.simantics.document.server.io.IConsole;
55 import org.simantics.document.server.request.ServerSCLHandlerValueRequest;
56 import org.simantics.document.server.request.ServerSCLValueRequest;
57 import org.simantics.document.server.serverResponse.ServerResponse;
58 import org.simantics.document.server.serverResponse.SuccessResponse;
59 import org.simantics.modeling.ModelingResources;
60 import org.simantics.modeling.scl.SCLRealm;
61 import org.simantics.modeling.scl.SCLSessionManager;
62 import org.simantics.modeling.services.CaseInsensitiveComponentFunctionNamingStrategy;
63 import org.simantics.modeling.services.ComponentNamingStrategy;
64 import org.simantics.operation.Layer0X;
65 import org.simantics.project.IProject;
66 import org.simantics.scl.compiler.types.TCon;
67 import org.simantics.scl.compiler.types.Type;
68 import org.simantics.scl.compiler.types.Types;
69 import org.simantics.scl.reflection.annotations.SCLValue;
70 import org.simantics.scl.runtime.SCLContext;
71 import org.simantics.scl.runtime.function.Function;
72 import org.simantics.scl.runtime.function.Function1;
73 import org.simantics.scl.runtime.function.FunctionImpl1;
74 import org.simantics.scl.runtime.function.FunctionImpl4;
75 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
76 import org.simantics.scl.runtime.tuple.Tuple;
77 import org.simantics.scl.runtime.tuple.Tuple0;
78 import org.simantics.scl.runtime.tuple.Tuple2;
79 import org.simantics.scl.runtime.tuple.Tuple3;
80 import org.simantics.scl.runtime.tuple.Tuple4;
81 import org.simantics.scl.runtime.tuple.Tuple5;
82 import org.simantics.simulation.experiment.IExperiment;
83 import org.simantics.simulation.ontology.SimulationResource;
84 import org.simantics.simulation.project.IExperimentManager;
85 import org.simantics.structural2.variables.Connection;
86 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
88 import gnu.trove.map.hash.THashMap;
90 public class Functions {
92 @SCLValue(type = "VariableMap")
93 public static VariableMap inputSpaceChildren = new VariableMapImpl() {
95 private Variable getProxy(ReadGraph graph, Variable context) throws DatabaseException {
96 Variable root = Variables.getRootVariable(graph);
97 return new DocumentProxyChildVariable(context, context, root, ProxyChildVariable.CONTEXT_BEGIN);
101 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
103 if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context);
104 return All.standardChildDomainChildren.getVariable(graph, context, name);
109 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
111 map = All.standardChildDomainChildren.getVariables(graph, context, map);
112 if(map == null) map = new THashMap<String,Variable>();
113 map.put(ProxyChildVariable.CONTEXT_BEGIN, getProxy(graph, context));
120 static class DocumentProxyChildVariable extends ProxyChildVariable {
122 public DocumentProxyChildVariable(Variable base, Variable parent, Variable other, String name) {
123 super(base, parent, other, name);
127 public Variable create(Variable base, Variable parent, Variable other, String name) {
128 return new DocumentProxyChildVariable(base, parent, other, name);
131 public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
133 if(CONTEXT_END.equals(name)) {
134 if(other instanceof ProxyChildVariable) {
135 // The context is also a proxy - let it do the job
136 return super.getPossibleChild(graph, name);
138 return new RootVariable(this, base.getRepresents(graph));
142 return super.getPossibleChild(graph, name);
146 public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
148 Collection<Variable> result = super.getChildren(graph);
149 if(!(base instanceof ProxyChildVariable)) {
150 result.add(new RootVariable(this, base.getRepresents(graph)));
158 static class RootVariable extends StandardGraphChildVariable {
160 public RootVariable(DocumentProxyChildVariable parent, Resource resource) {
161 super(parent, null, resource);
165 public String getName(ReadGraph graph) throws DatabaseException {
166 return ProxyChildVariable.CONTEXT_END;
169 @SuppressWarnings("deprecation")
171 public Variable getNameVariable(ReadGraph graph) throws DatabaseException {
172 return new ConstantPropertyVariable(this, Variables.NAME, ProxyChildVariable.CONTEXT_END, Bindings.STRING);
177 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
178 public static Variable input(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
179 Variable session = graph.syncRequest(new ProxySessionRequest(context));
180 DocumentationResource DOC = DocumentationResource.getInstance(graph);
181 String uri = session.getPossiblePropertyValue(graph, DOC.Session_inputURI);
183 // TODO HAXX - Please fix this
184 // we have no URI so this probably means that someone has inserted a non-session
185 // into the proxy variable => return that instead
188 return Variables.getVariable(graph, uri);
191 public static Variable stateVariable(ReadGraph graph, Variable self) throws DatabaseException {
192 Variable session = graph.syncRequest(new ProxySessionRequest(self));
194 throw new DatabaseException("No state for " + self.getURI(graph));
195 return session.getPossibleChild(graph, "__scl__");
198 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
199 public static Variable state(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
200 Variable session = graph.syncRequest(new ProxySessionRequest(context));
202 throw new DatabaseException("No state for " + context.getURI(graph));
203 return session.getPossibleChild(graph, "__scl__");
206 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
207 public static Variable icstate(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
208 Variable session = graph.syncRequest(new ProxySessionRequest(context));
209 return session.getPossibleChild(graph, "__icstate__");
212 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
213 public static Variable session(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
214 return graph.syncRequest(new ProxySessionRequest(context));
217 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
218 public static Variable experiment(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
219 // Try if experiment (run) has been used as the input
220 Variable var = input(graph, converter, context);
221 SimulationResource SR = SimulationResource.getInstance(graph);
222 while(var != null && !graph.isInstanceOf(var.getRepresents(graph), SR.Run)) {
223 var = var.getParent(graph);
227 IExperiment exp = getExperiment(graph, var);
235 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
236 public static Variable model(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
237 Variable var = input(graph, converter, context);
238 ModelingResources MOD = ModelingResources.getInstance(graph);
239 while(var != null && !graph.isInstanceOf(var.getRepresents(graph), MOD.StructuralModel)) {
240 var = var.getParent(graph);
246 private static Collection<Variable> getBroadcasted(ReadGraph graph, Variable target) throws DatabaseException {
248 ArrayList<Variable> result = new ArrayList<Variable>();
250 DocumentationResource DOC = DocumentationResource.getInstance(graph);
252 Variable broadcasted = target.getPossibleProperty(graph, DOC.Relations_broadcasted);
253 if(broadcasted != null) result.add(broadcasted);
255 for(Variable child : DocumentServerUtils.getChildrenInOrdinalOrder(graph, target)) {
256 result.addAll(getBroadcasted(graph, child));
263 private static List<Command> getCommands(ReadGraph graph, Collection<Variable> commandVariables, String trigger, CommandContext constants, boolean broadcast) throws DatabaseException {
265 if(commandVariables.isEmpty()) return Collections.emptyList();
268 TreeMap<Integer, List<Command>> sequences = new TreeMap<Integer, List<Command>>();
270 DocumentationResource DOC = DocumentationResource.getInstance(graph);
273 for (Variable c : commandVariables) {
276 t = c.getName(graph);
278 Connection conn = c.getValue(graph);
279 Variable targetConnectionPoint = DocumentServerUtils.getPossibleCommandTriggerConnectionPoint(graph, c, conn);
280 if (targetConnectionPoint != null) {
281 Variable target = targetConnectionPoint.getParent(graph);
282 if (target != null) {
284 Boolean enabled = target.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
285 if(enabled != null && !enabled) continue;
293 String o = c.getPossiblePropertyValue(graph, "ordinal");
295 ordinal = Integer.parseInt(o);
296 } catch (NumberFormatException e) {}
299 String constantKey = target.getPossiblePropertyValue(graph, "constantKey");
300 String constantValue = target.getPossiblePropertyValue(graph, "constantValue");
302 CommandContextMutable newConstants = (CommandContextMutable)constants;
303 if(constantKey != null && constantValue != null) {
304 if(!constantKey.isEmpty()) {
305 newConstants = new CommandContextImpl().merge(constants);
306 newConstants.putString(constantKey, constantValue);
310 String requiredKey = target.getPossiblePropertyValue(graph, "requiredKey");
311 if(requiredKey != null && !requiredKey.isEmpty()) {
312 if (newConstants == constants) {
313 newConstants = new CommandContextImpl().merge(constants);
315 newConstants.putRow(CommandContext.REQUIRED_KEYS, Collections.<Object>singletonList(requiredKey));
318 String forbiddenKey = target.getPossiblePropertyValue(graph, "forbiddenKey");
319 if(forbiddenKey != null && !forbiddenKey.isEmpty()) {
320 if (newConstants == constants) {
321 newConstants = new CommandContextImpl().merge(constants);
323 newConstants.putRow(CommandContext.FORBIDDEN_KEYS, Collections.<Object>singletonList(forbiddenKey));
326 if(DOC.Relations_broadcast.equals(targetConnectionPoint.getPredicateResource(graph))) {
328 // This is a broadcast terminal of a container
329 List<Command> broadcastCommands = getCommands(graph, getBroadcasted(graph, target), t, newConstants, true);
330 sequences.put(ordinal, broadcastCommands);
334 Command command = new Command(DocumentServerUtils.getId(graph, target), t,
335 targetConnectionPoint.getName(graph), newConstants);
336 sequences.put(ordinal, Collections.singletonList(command));
344 List<Command> commands = new ArrayList<Command>();
345 for (List<Command> commandList : sequences.values()) {
346 for (Command command : commandList) {
347 commands.add(command);
360 * @throws DatabaseException
362 public static List<Command> commandList(ReadGraph graph, Variable variable) throws DatabaseException {
363 return getCommands(graph, DocumentServerUtils.getTriggerCommands(graph, variable.getParent(graph)), null, new CommandContextImpl(), false);
372 * @throws DatabaseException
374 public static List<DataDefinition> dataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {
375 DocumentationResource DOC = DocumentationResource.getInstance(graph);
376 ArrayList<DataDefinition> dataDefinitions = new ArrayList<DataDefinition>();
377 // Find data definition connections
378 for (Variable dataDefinitionRelation : DocumentServerUtils.getDataDefinitions(graph, variable.getParent(graph))) {
379 Connection dataDefinitionConnection = dataDefinitionRelation.getValue(graph);
380 // Find data the other end of definition connection
381 Collection<Variable> dataDefinitionProviders = DocumentServerUtils.getPossibleOtherConnectionPoints(graph,
382 dataDefinitionRelation, dataDefinitionConnection);
383 if (dataDefinitionProviders != null) {
385 for(Variable dataDefinitionProvider : dataDefinitionProviders) {
387 Variable dataDefinition = dataDefinitionProvider.getParent(graph);
388 if (dataDefinition != null) {
389 // Found other end. Is should contain ONE data
390 // definition connection to the actual data
391 Collection<Variable> dataCollection = DocumentServerUtils.getDataRelations(graph, dataDefinition);
392 if (dataCollection.size() == 1) {
393 Variable dataRelation = dataCollection.iterator().next();
394 Connection dataConnection = dataRelation.getValue(graph);
395 // Find data the other end of definition connection
396 Variable dataConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph,
397 dataRelation, dataConnection);
398 if (dataConnectionPoint != null) {
399 Variable data = dataConnectionPoint.getParent(graph);
400 Resource type = dataDefinition.getPossibleType(graph, DOC.Components_Component);
402 if (graph.isInheritedFrom(type, DOC.Components_DefVar)) {
404 String sourceProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_source,
406 String targetProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_target,
409 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
410 sourceProperty, targetProperty));
412 } else if (graph.isInheritedFrom(type, DOC.Components_DefVars)) {
414 List<String> sourcesProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_sources), String.class);
415 List<String> targetsProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_targets), String.class);
417 for (int i = 0; i < Math.min(sourcesProperty.size(), targetsProperty.size()); i++) {
418 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
419 sourcesProperty.get(i), targetsProperty.get(i)));
428 return dataDefinitions;
431 @SuppressWarnings("unchecked")
432 private static <T> List<T> toList(Object o, Class<T> c) {
433 List<T> result = null;
434 if (o instanceof List) {
436 } else if (o instanceof Object[]) {
437 result = new ArrayList<T>(((Object[])o).length);
438 for (T item : (T[])o) {
443 return Collections.<T>emptyList();
447 public static AbstractEventHandler emptyOnClick(ReadGraph graph) throws DatabaseException {
448 return new EventHandler() {
451 public ServerResponse handle(ReadGraph graph, CommandContext parameters) throws DatabaseException {
458 public static AbstractEventHandler writeEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
460 final Session session = graph.getSession();
462 return new AbstractEventHandler() {
465 public CommandResult handle(final CommandContext parameters) {
467 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
471 String result = session.sync(new WriteResultRequest<String>() {
474 public String perform(WriteGraph graph) throws DatabaseException {
475 SCLContext sclContext = SCLContext.getCurrent();
476 Object oldGraph = sclContext.put("graph", graph);
477 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
479 Function1<String,String> pf = new FunctionImpl1<String,String>() {
481 public String apply(String key) {
482 return parameters.getString(key);
485 Object response = (String)fn.apply(variable, pf);
486 if(response instanceof String) {
487 return (String)response;
490 } catch (Throwable t) {
493 sclContext.put("graph", oldGraph);
494 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
503 return new SuccessResponse(result);
505 } catch (Throwable e) {
506 Logger.defaultLogError(e);
507 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
515 public static AbstractEventHandler readEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
517 final Session session = graph.getSession();
519 return new AbstractEventHandler() {
522 public CommandResult handle(final CommandContext parameters) {
524 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
528 String result = session.sync(new UniqueRead<String>() {
531 public String perform(ReadGraph graph) throws DatabaseException {
532 SCLContext sclContext = SCLContext.getCurrent();
533 Object oldGraph = sclContext.put("graph", graph);
534 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
536 Function1<String,String> pf = new FunctionImpl1<String,String>() {
538 public String apply(String key) {
539 return parameters.getString(key);
542 Object response = (String)fn.apply(variable, pf);
543 if(response instanceof String) {
544 return (String)response;
547 } catch (Throwable t) {
550 sclContext.put("graph", oldGraph);
551 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
560 return new SuccessResponse(result);
562 } catch (Throwable e) {
563 Logger.defaultLogError(e);
564 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
572 public static AbstractEventHandler readEventHandler2(ReadGraph graph, final Function fn) {
574 final Session session = graph.getSession();
576 return new AbstractEventHandler() {
579 public CommandResult handle(final CommandContext parameters) {
581 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
585 CommandResult result = session.sync(new UniqueRead<CommandResult>() {
588 public CommandResult perform(ReadGraph graph) throws DatabaseException {
589 SCLContext sclContext = SCLContext.getCurrent();
590 Object oldGraph = sclContext.put("graph", graph);
591 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
593 Object response = fn.apply(parameters);
594 if(response instanceof CommandResult) {
595 return (CommandResult)response;
598 } catch (Throwable t) {
601 sclContext.put("graph", oldGraph);
602 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
613 } catch (Throwable e) {
614 Logger.defaultLogError(e);
615 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
623 public static AbstractEventHandler responseHandler(ReadGraph graph, Variable self, String function) throws DatabaseException {
625 Variable anyFunction = self.browse(graph, ".#" + function);
626 if(anyFunction == null) return null;
628 final List<TCon> effects = ServerSCLHandlerValueRequest.getEffects(graph, anyFunction);
630 final Function1<CommandContext, CommandResult> fn = anyFunction.getValue(graph);
631 String expression = anyFunction.getPropertyValue(graph, "expression");
633 final Session session = graph.getSession();
635 return new AbstractResponseHandler(expression) {
637 private String formatError(RequestProcessor proc, Throwable t) {
641 return proc.syncRequest(new UniqueRead<String>() {
644 public String perform(ReadGraph graph) throws DatabaseException {
645 Variable proxy = ProxyVariables.proxyVariableRoot(graph, anyFunction);
646 String uri2 = proxy.getURI(graph);
647 String uri = self.getParent(graph).getURI(graph);
649 String path = uri.substring(uri2.length());
651 String expr = anyFunction.getPossiblePropertyValue(graph, "expression");
652 StringBuilder message = new StringBuilder();
653 message.append("Handler execution failed\n");
654 message.append(" handler=" + path + "\n");
655 message.append(" expression=" + expr + "\n");
656 message.append(" message=" + t.getMessage() + "\n");
658 StringWriter sw = new StringWriter();
659 t.printStackTrace(new PrintWriter(sw));
660 message.append(" stack trace=" + sw);
662 return message.toString();
667 } catch (DatabaseException e) {
669 return e.getMessage();
676 public CommandResult handle(final CommandContext parameters) {
678 IConsole console = parameters.getValue("__console__");
679 SCLReportingHandler printer = (console != null) ? new ConsoleSCLReportingHandler(console)
680 : (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
684 Object result = null;
685 if(effects.contains(Types.WRITE_GRAPH)) {
687 result = session.syncRequest(new WriteResultRequest<Object>() {
690 public Object perform(WriteGraph graph)
691 throws DatabaseException {
692 SCLContext sclContext = SCLContext.getCurrent();
693 Object oldGraph = sclContext.put("graph", graph);
694 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
696 Object response = fn.apply(parameters);
698 } catch (Throwable t) {
699 return new org.simantics.document.server.serverResponse.Error(formatError(graph, t));
701 sclContext.put("graph", oldGraph);
702 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
708 } else if(effects.contains(Types.READ_GRAPH)) {
710 result = session.sync(new UniqueRead<Object>() {
713 public Object perform(ReadGraph graph) throws DatabaseException {
715 SCLContext sclContext = SCLContext.getCurrent();
716 Object oldGraph = sclContext.put("graph", graph);
717 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
720 Object response = fn.apply(parameters);
722 } catch (Throwable t) {
723 return new org.simantics.document.server.serverResponse.Error(formatError(graph, t));
725 sclContext.put("graph", oldGraph);
726 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
734 SCLContext sclContext = SCLContext.getCurrent();
735 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
737 result = fn.apply(parameters);
739 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
744 if (result instanceof org.simantics.document.server.serverResponse.Error) {
745 return (CommandResult)result;
748 if (result instanceof CommandResult) {
749 return (CommandResult)result;
751 CommandContextMutable assignments = new CommandContextImpl();
752 assignments.putValue("result", result);
753 return new ServerResponse(200, "", assignments);
756 } catch (Throwable e) {
757 return new org.simantics.document.server.serverResponse.Error(formatError(Simantics.getSession(), e));
765 public static AbstractEventHandler writeEventHandler2(ReadGraph graph, final Function fn) {
767 final Session session = graph.getSession();
769 return new AbstractEventHandler() {
772 public CommandResult handle(final CommandContext parameters) {
774 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
778 CommandResult result = session.syncRequest(new WriteResultRequest<CommandResult>() {
781 public CommandResult perform(WriteGraph graph) throws DatabaseException {
782 SCLContext sclContext = SCLContext.getCurrent();
783 Object oldGraph = sclContext.put("graph", graph);
784 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
786 Object response = fn.apply(parameters);
787 if(response instanceof CommandResult) {
788 return (CommandResult)response;
791 } catch (Throwable t) {
794 sclContext.put("graph", oldGraph);
795 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
806 } catch (Throwable e) {
807 Logger.defaultLogError(e);
808 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
816 public static AbstractEventHandler eventHandler2(ReadGraph graph, final Function fn) {
818 return new AbstractEventHandler() {
821 public CommandResult handle(final CommandContext parameters) {
823 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
827 SCLContext sclContext = SCLContext.getCurrent();
828 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
830 Object response = fn.apply(parameters);
831 if(response instanceof CommandResult) {
832 return (CommandResult)response;
835 } catch (Throwable t) {
838 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
843 } catch (Throwable e) {
844 Logger.defaultLogError(e);
845 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
853 public static AbstractEventHandler eventHandler(ReadGraph graph, final Function fn) {
855 return new AbstractEventHandler() {
858 public CommandResult handle(final CommandContext parameters) {
860 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
866 SCLContext sclContext = SCLContext.getCurrent();
867 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
869 Function1<String,String> pf = new FunctionImpl1<String,String>() {
871 public String apply(String key) {
872 return parameters.getString(key);
875 Object response = (String)fn.apply(pf);
876 if(response instanceof String) {
877 result = (String)response;
879 } catch (Throwable t) {
882 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
885 return new SuccessResponse(result);
887 } catch (Throwable e) {
888 Logger.defaultLogError(e);
889 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
897 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
898 public static Object sclValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
899 return ServerSCLValueRequest.compileAndEvaluate(graph, context);
902 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
903 public static Object sclHandlerValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
904 return ServerSCLHandlerValueRequest.compileAndEvaluate(graph, context);
907 @SCLValue(type = "ReadGraph -> Resource -> Resource -> ComponentNamingStrategy")
908 public static ComponentNamingStrategy componentNamingStrategy(ReadGraph graph, Resource converter, Resource context) throws DatabaseException {
909 return createComponentNamingStrategy(graph);
912 public static CaseInsensitiveComponentFunctionNamingStrategy createComponentNamingStrategy(ReadGraph graph) throws DatabaseException {
913 Layer0X L0X = Layer0X.getInstance(graph);
914 @SuppressWarnings({ "unchecked", "rawtypes" })
915 final Function dependencies = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());
916 @SuppressWarnings("rawtypes")
917 Function moduleNameFunction = new FunctionImpl4<ReadGraph, Resource, String, Integer, List<Map<String, Object>>>() {
919 public Object apply(ReadGraph p0, Resource p1, String p2) {
920 return apply(p0, p1, p2);
922 @SuppressWarnings("unchecked")
924 public List<Map<String, Object>> apply(ReadGraph graph, Resource model, String search, Integer maxResults) {
925 return (List<Map<String, Object>>)dependencies.apply(graph, model, search, maxResults);
928 return new CaseInsensitiveComponentFunctionNamingStrategy("%s%02d", moduleNameFunction);
931 public static IExperiment getExperiment(ReadGraph graph, Variable variable) throws DatabaseException {
932 if (variable == null)
935 SimulationResource SIMU = SimulationResource.getInstance(graph);
937 Variable var = variable;
938 Resource represents = var.getRepresents(graph);
939 Resource activeRun = null;
940 if (represents != null && graph.isInstanceOf(represents, SIMU.Run)) {
941 activeRun = represents;
944 IProject project = Simantics.peekProject();
945 if (activeRun != null && project != null) {
946 IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
948 return expMan.getExperiment(NameUtils.getSafeName(graph, activeRun));
954 public static CommandContextMutable putTuple(CommandContextMutable context, String key, Object tuple) {
955 List<Object> list = new ArrayList<Object>();
956 if (tuple instanceof Tuple) {
957 Collections.addAll(list, ((Tuple)tuple).toArray());
961 context.putRow(key, list);
965 public static List<Object> getTuples(CommandContext context, String key) {
966 List<List<Object>> rows = context.getRows(key);
967 List<Object> tuples = new ArrayList<Object>();
969 for (List<Object> row : rows) {
970 switch (row.size()) {
971 case 0: tuples.add(Tuple0.INSTANCE); break;
972 case 1: tuples.add(row.get(1)); break;
973 case 2: tuples.add(new Tuple2(row.get(0), row.get(1))); break;
974 case 3: tuples.add(new Tuple3(row.get(0), row.get(1), row.get(2))); break;
975 case 4: tuples.add(new Tuple4(row.get(0), row.get(1), row.get(2), row.get(3))); break;
976 case 5: tuples.add(new Tuple5(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4))); break;
983 public static String printContext(CommandContext context) {
984 return context.toString();
987 @SCLValue(type = "AbstractEventHandler")
988 public static AbstractEventHandler emptyEvent = new AbstractEventHandler() {
991 public CommandResult handle(CommandContext context) {
997 public static String sclStateKey(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
999 String baseURI = base.getURI(graph);
1001 String selfURI = self.getURI(graph);
1003 String prefix = selfURI.substring(0, selfURI.indexOf(ProxyChildVariable.CONTEXT_BEGIN));
1004 String suffix = selfURI.substring(selfURI.lastIndexOf(ProxyChildVariable.CONTEXT_END) + ProxyChildVariable.CONTEXT_END.length());
1005 String stripped = prefix + suffix;
1007 String relative = Variables.getRelativeRVI(baseURI, stripped);
1009 return Variables.getRVI(relative, ref);
1013 public static Variable sclStateVariable(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1015 String id = sclStateKey(graph, base, self, ref);
1017 Variable sclVar = base.getPossibleChild(graph, "__scl__");
1018 if(sclVar == null) return null;
1020 return sclVar.getPossibleProperty(graph, id);
1024 public static Object sclStateValueOrDefault(ReadGraph graph, Variable base, Variable self, String ref, Object defaultValue) throws DatabaseException {
1026 Variable stateVariable = sclStateVariable(graph, base, self, ref);
1027 if (stateVariable != null) {
1029 return stateVariable.getValue(graph);
1033 String id = sclStateKey(graph, base, self, ref);
1035 SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph) + "/__scl__");
1036 realm.getConnection().setVariable(id, getSCLType(defaultValue), defaultValue);
1038 return defaultValue;
1043 public static void setSclStateValue(WriteGraph graph, Variable base, Variable self, String ref, Object value) throws DatabaseException {
1045 String id = sclStateKey(graph, base, self, ref);
1047 SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph)+"/__scl__");
1048 realm.getConnection().setVariable(id, getSCLType(value), value);
1049 realm.refreshVariablesSync();
1053 public static Object projectComponentState(ReadGraph graph, Variable self, String ref, Object defaultValue) throws DatabaseException {
1054 Resource project = Simantics.getProjectResource();
1055 Variable component = self.getParent(graph);
1056 Variable projectVariable = Variables.getVariable(graph, project);
1057 return sclStateValueOrDefault(graph, projectVariable, component, ref, defaultValue);
1060 public static void setProjectComponentState(WriteGraph graph, Variable self, String ref, Object value) throws DatabaseException {
1061 Resource project = Simantics.getProjectResource();
1062 Variable component = self.getParent(graph);
1063 Variable projectVariable = Variables.getVariable(graph, project);
1064 setSclStateValue(graph, projectVariable, component, ref, value);
1067 private static Type getSCLType(Object value) throws DatabaseException {
1068 Binding b = Bindings.getBindingUnchecked(value.getClass());
1069 Datatype t = b.type();
1070 if(Datatypes.STRING.equals(t)) return Types.STRING;
1071 if(Datatypes.DOUBLE.equals(t)) return Types.DOUBLE;
1072 throw new DatabaseException("Type not supported");
1075 public static List<Variable> documentModelContribution(ReadGraph graph, Resource doc) throws DatabaseException {
1076 Resource project = Simantics.getProjectResource();
1077 ArrayList<Variable> result = new ArrayList<Variable>();
1078 for(Resource model : graph.syncRequest(new ProjectModels(project))) {
1079 result.add(Variables.getVariable(graph, model));
1084 public static String documentModelContributionLabel(ReadGraph graph, Variable var) throws DatabaseException {
1085 return var.getName(graph);
1088 public static Object getPropertyValueCached(ReadGraph graph, Variable variable, String name, Binding binding) throws DatabaseException {
1089 Variable property = graph.syncRequest(new VariableProperty(variable, name));
1090 return graph.syncRequest(new VariableValueWithBinding<Object>(property, binding));
1093 public static class ParentExistsRequest extends VariableRead<Boolean> {
1095 public ParentExistsRequest(Variable parent) {
1100 public Boolean perform(ReadGraph graph) throws DatabaseException {
1102 Variable existsProperty = variable.getPossibleProperty(graph, "exists");
1103 if(existsProperty == null) return true;
1105 Boolean exists = existsProperty.getPossibleValue(graph, Bindings.BOOLEAN);
1106 if (exists == null || !exists) return false;
1108 return graph.syncRequest(new ParentExistsRequest(variable.getParent(graph)));
1114 public static class PathExistsRequest extends VariableRead<Boolean> {
1116 public PathExistsRequest(Variable variable) {
1121 public Boolean perform(ReadGraph graph) throws DatabaseException {
1123 Variable widget = variable.getParent(graph);
1125 Boolean exists = widget.getPossiblePropertyValue(graph, "exists");
1126 if (exists == null || !exists) return false;
1128 if (!graph.syncRequest(new ParentExistsRequest(widget.getParent(graph)))) return false;
1130 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1131 Collection <Variable> cps = widget.getProperties(graph, DOC.Relations_parentRelation);
1132 for (Variable cp : cps) {
1134 Connection conn = cp.getValue(graph);
1135 Variable otherCp = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, cp, conn);
1136 if (otherCp != null) {
1137 Variable parentWidget = otherCp.getParent(graph);
1138 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1142 Variable parentCp = graph.sync(new UnaryRead<Connection, Variable>(conn) {
1144 public Variable perform(ReadGraph graph) throws DatabaseException {
1145 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1146 Collection<VariableConnectionPointDescriptor> descs = parameter.getConnectionPointDescriptors(graph, null);
1148 for(VariableConnectionPointDescriptor desc : descs) {
1149 if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
1150 return desc.getVariable(graph);
1156 if (parentCp != null) {
1157 Variable parentWidget = parentCp.getParent(graph);
1158 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1165 Resource type = widget.getType(graph);
1166 return graph.isInheritedFrom(type, DOC.Components_ParentlessComponent) ||
1167 (graph.isInheritedFrom(type, DOC.DocumentComponent) && cps.isEmpty());
1171 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1172 public static boolean pathExists(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1173 return graph.syncRequest(new PathExistsRequest(context));
1176 static class ConsoleSCLReportingHandler implements SCLReportingHandler {
1178 private final IConsole console;
1180 ConsoleSCLReportingHandler(IConsole console) {
1181 this.console = console;
1185 public void print(String text) {
1186 console.addMessage(text);
1190 public void printError(String error) {
1191 console.addMessage(error);
1195 public void printCommand(String command) {
1196 console.addMessage(command);
1200 public void didWork(double amount) {
1201 console.addMessage("didWork " + amount);