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;
8 import java.util.HashMap;
11 import java.util.TreeMap;
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;
103 import gnu.trove.map.hash.THashMap;
105 public class Functions {
107 private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Functions.class);
109 private static class PrimitivePropertyStatementsProcedure implements AsyncProcedure<DirectStatements> {
111 public DirectStatements result;
114 public void execute(AsyncReadGraph graph, DirectStatements result) {
115 this.result = result;
119 public void exception(AsyncReadGraph graph, Throwable throwable) {
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) {
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);
139 exceptionMap = propertyExceptions.getValue(graph);
140 } catch (DatabaseException e1) {
141 Logger.defaultLogError(e1);
147 label = property.getLabel(graph);
148 } catch (DatabaseException e2) {
151 exceptionMap.put(label, e);
156 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
157 return All.getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
161 public Map<String, Variable> getVariables(final ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
163 if(map == null) map = new HashMap<String,Variable>();
165 Variable parent = context.getParent(graph);
167 DocumentationResource DOC = DocumentationResource.getInstance(graph);
169 if(parent instanceof StandardProceduralChildVariable) {
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);
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);
192 Resource parentRes = parent.getRepresents(graph);
194 Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_commands);
195 storePropertyValueAndExceptions(graph, parent, "commands", prop, map);
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);
203 DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class);
204 PrimitivePropertyStatementsProcedure foo = new PrimitivePropertyStatementsProcedure();
206 dqs.forEachDirectPersistentStatement(graph, parentRes, foo);
208 for(Statement stm : foo.result) {
209 Resource predicate = stm.getPredicate();
210 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
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);
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));
231 @SCLValue(type = "VariableMap")
232 public static VariableMap inputSpaceChildren = new VariableMapImpl() {
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);
240 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
242 if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context);
243 return All.standardChildDomainChildren.getVariable(graph, context, name);
248 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
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));
259 static class DocumentProxyChildVariable extends ProxyChildVariable {
261 public DocumentProxyChildVariable(Variable base, Variable parent, Variable other, String name) {
262 super(base, parent, other, name);
266 public Variable create(Variable base, Variable parent, Variable other, String name) {
267 return new DocumentProxyChildVariable(base, parent, other, name);
270 public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
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);
277 return new RootVariable(this, base.getRepresents(graph));
281 return super.getPossibleChild(graph, name);
285 public Collection<Variable> getChildren(ReadGraph graph) throws DatabaseException {
287 Collection<Variable> result = super.getChildren(graph);
288 if(!(base instanceof ProxyChildVariable)) {
289 result.add(new RootVariable(this, base.getRepresents(graph)));
297 static class RootVariable extends StandardGraphChildVariable {
299 public RootVariable(DocumentProxyChildVariable parent, Resource resource) {
300 super(parent, null, resource);
304 public String getName(ReadGraph graph) throws DatabaseException {
305 return ProxyChildVariable.CONTEXT_END;
308 @SuppressWarnings("deprecation")
310 public Variable getNameVariable(ReadGraph graph) throws DatabaseException {
311 return new ConstantPropertyVariable(this, Variables.NAME, ProxyChildVariable.CONTEXT_END, Bindings.STRING);
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);
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
327 return Variables.getVariable(graph, uri);
330 public static Variable stateVariable(ReadGraph graph, Variable self) throws DatabaseException {
331 Variable session = graph.syncRequest(new ProxySessionRequest(self));
333 throw new DatabaseException("No state for " + self.getURI(graph));
334 return session.getPossibleChild(graph, "__scl__");
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));
341 throw new DatabaseException("No state for " + context.getURI(graph));
342 return session.getPossibleChild(graph, "__scl__");
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__");
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));
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);
366 IExperiment exp = getExperiment(graph, var);
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);
385 private static Collection<Variable> getBroadcasted(ReadGraph graph, Variable target) throws DatabaseException {
387 ArrayList<Variable> result = new ArrayList<Variable>();
389 DocumentationResource DOC = DocumentationResource.getInstance(graph);
391 Variable broadcasted = target.getPossibleProperty(graph, DOC.Relations_broadcasted);
392 if(broadcasted != null) result.add(broadcasted);
394 for(Variable child : DocumentServerUtils.getChildrenInOrdinalOrder(graph, target)) {
395 result.addAll(getBroadcasted(graph, child));
402 private static List<Command> getCommands(ReadGraph graph, Collection<Variable> commandVariables, String trigger, CommandContext constants, boolean broadcast) throws DatabaseException {
404 if(commandVariables.isEmpty()) return Collections.emptyList();
407 TreeMap<Integer, List<Command>> sequences = new TreeMap<Integer, List<Command>>();
409 DocumentationResource DOC = DocumentationResource.getInstance(graph);
412 for (Variable c : commandVariables) {
415 t = c.getName(graph);
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) {
423 Boolean enabled = target.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
424 if(enabled != null && !enabled) continue;
432 String o = c.getPossiblePropertyValue(graph, "ordinal");
434 ordinal = Integer.parseInt(o);
435 } catch (NumberFormatException e) {}
438 String constantKey = target.getPossiblePropertyValue(graph, "constantKey");
439 String constantValue = target.getPossiblePropertyValue(graph, "constantValue");
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);
449 String requiredKey = target.getPossiblePropertyValue(graph, "requiredKey");
450 if(requiredKey != null && !requiredKey.isEmpty()) {
451 if (newConstants == constants) {
452 newConstants = new CommandContextImpl().merge(constants);
454 newConstants.putRow(CommandContext.REQUIRED_KEYS, Collections.<Object>singletonList(requiredKey));
457 String forbiddenKey = target.getPossiblePropertyValue(graph, "forbiddenKey");
458 if(forbiddenKey != null && !forbiddenKey.isEmpty()) {
459 if (newConstants == constants) {
460 newConstants = new CommandContextImpl().merge(constants);
462 newConstants.putRow(CommandContext.FORBIDDEN_KEYS, Collections.<Object>singletonList(forbiddenKey));
465 if(DOC.Relations_broadcast.equals(targetConnectionPoint.getPredicateResource(graph))) {
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);
473 Command command = new Command(DocumentServerUtils.getId(graph, target), t,
474 targetConnectionPoint.getName(graph), newConstants);
475 sequences.put(ordinal, Collections.singletonList(command));
483 List<Command> commands = new ArrayList<Command>();
484 for (List<Command> commandList : sequences.values()) {
485 for (Command command : commandList) {
486 commands.add(command);
499 * @throws DatabaseException
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);
511 * @throws DatabaseException
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) {
524 for(Variable dataDefinitionProvider : dataDefinitionProviders) {
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);
541 if (graph.isInheritedFrom(type, DOC.Components_DefVar)) {
543 String sourceProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_source,
545 String targetProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_target,
548 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
549 sourceProperty, targetProperty));
551 } else if (graph.isInheritedFrom(type, DOC.Components_DefVars)) {
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);
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)));
567 return dataDefinitions;
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) {
575 } else if (o instanceof Object[]) {
576 result = new ArrayList<T>(((Object[])o).length);
577 for (T item : (T[])o) {
582 return Collections.<T>emptyList();
586 public static AbstractEventHandler emptyOnClick(ReadGraph graph) throws DatabaseException {
587 return new EventHandler() {
589 public ServerResponse handle(ReadGraph graph, CommandContext parameters) throws DatabaseException {
595 public static AbstractEventHandler writeEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
597 final Session session = graph.getSession();
599 return new AbstractEventHandler() {
602 public CommandResult handle(final CommandContext parameters) {
604 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
608 String result = session.sync(new WriteResultRequest<String>() {
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);
616 Function1<String,String> pf = new FunctionImpl1<String,String>() {
618 public String apply(String key) {
619 return parameters.getString(key);
622 Object response = (String)fn.apply(variable, pf);
623 if(response instanceof String) {
624 return (String)response;
627 } catch (Throwable t) {
630 sclContext.put("graph", oldGraph);
631 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
640 return new SuccessResponse(result);
642 } catch (Throwable e) {
643 Logger.defaultLogError(e);
644 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
652 public static AbstractEventHandler readEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
654 final Session session = graph.getSession();
656 return new AbstractEventHandler() {
659 public CommandResult handle(final CommandContext parameters) {
661 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
665 String result = session.sync(new UniqueRead<String>() {
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);
673 Function1<String,String> pf = new FunctionImpl1<String,String>() {
675 public String apply(String key) {
676 return parameters.getString(key);
679 Object response = (String)fn.apply(variable, pf);
680 if(response instanceof String) {
681 return (String)response;
684 } catch (Throwable t) {
687 sclContext.put("graph", oldGraph);
688 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
697 return new SuccessResponse(result);
699 } catch (Throwable e) {
700 Logger.defaultLogError(e);
701 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
709 public static AbstractEventHandler readEventHandler2(ReadGraph graph, final Function fn) {
711 final Session session = graph.getSession();
713 return new AbstractEventHandler() {
716 public CommandResult handle(final CommandContext parameters) {
718 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
722 CommandResult result = session.sync(new UniqueRead<CommandResult>() {
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);
730 Object response = fn.apply(parameters);
731 if(response instanceof CommandResult) {
732 return (CommandResult)response;
735 } catch (Throwable t) {
738 sclContext.put("graph", oldGraph);
739 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
750 } catch (Throwable e) {
751 Logger.defaultLogError(e);
752 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
760 public static AbstractEventHandler responseHandler(ReadGraph graph, Variable self, String function) throws DatabaseException {
762 Variable anyFunction = self.browse(graph, ".#" + function);
763 if(anyFunction == null) return null;
765 final List<TCon> effects = ServerSCLHandlerValueRequest.getEffects(graph, anyFunction);
767 final Function1<CommandContext, CommandResult> fn = anyFunction.getValue(graph);
768 String expression = anyFunction.getPropertyValue(graph, "expression");
770 final Session session = graph.getSession();
772 return new AbstractResponseHandler(expression) {
774 private String formatError(RequestProcessor proc, Throwable t) {
778 return proc.syncRequest(new UniqueRead<String>() {
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);
786 String path = uri.substring(uri2.length());
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");
795 StringWriter sw = new StringWriter();
796 t.printStackTrace(new PrintWriter(sw));
797 message.append(" stack trace=" + sw);
799 return message.toString();
804 } catch (DatabaseException e) {
806 return e.getMessage();
813 public CommandResult handle(final CommandContext parameters) {
815 IConsole console = parameters.getValue("__console__");
816 SCLReportingHandler printer = (console != null) ? new ConsoleSCLReportingHandler(console)
817 : (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
821 Object result = null;
822 if(effects.contains(Types.WRITE_GRAPH)) {
824 result = session.syncRequest(new WriteResultRequest<Object>() {
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);
833 Object response = fn.apply(parameters);
835 } catch (Throwable t) {
836 return new org.simantics.document.server.serverResponse.Error(formatError(graph, t));
838 sclContext.put("graph", oldGraph);
839 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
845 } else if(effects.contains(Types.READ_GRAPH)) {
847 result = session.sync(new UniqueRead<Object>() {
850 public Object perform(ReadGraph graph) throws DatabaseException {
852 SCLContext sclContext = SCLContext.getCurrent();
853 Object oldGraph = sclContext.put("graph", graph);
854 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
857 Object response = fn.apply(parameters);
859 } catch (Throwable t) {
860 return new org.simantics.document.server.serverResponse.Error(formatError(graph, t));
862 sclContext.put("graph", oldGraph);
863 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
871 SCLContext sclContext = SCLContext.getCurrent();
872 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
874 result = fn.apply(parameters);
876 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
881 if (result instanceof org.simantics.document.server.serverResponse.Error) {
882 return (CommandResult)result;
885 if (result instanceof CommandResult) {
886 return (CommandResult)result;
888 CommandContextMutable assignments = new CommandContextImpl();
889 assignments.putValue("result", result);
890 return new ServerResponse(200, "", assignments);
893 } catch (Throwable e) {
894 return new org.simantics.document.server.serverResponse.Error(formatError(Simantics.getSession(), e));
902 public static AbstractEventHandler writeEventHandler2(ReadGraph graph, final Function fn) {
904 final Session session = graph.getSession();
906 return new AbstractEventHandler() {
909 public CommandResult handle(final CommandContext parameters) {
911 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
915 CommandResult result = session.syncRequest(new WriteResultRequest<CommandResult>() {
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);
923 Object response = fn.apply(parameters);
924 if(response instanceof CommandResult) {
925 return (CommandResult)response;
928 } catch (Throwable t) {
931 sclContext.put("graph", oldGraph);
932 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
943 } catch (Throwable e) {
944 Logger.defaultLogError(e);
945 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
953 public static AbstractEventHandler eventHandler2(ReadGraph graph, final Function fn) {
955 return new AbstractEventHandler() {
958 public CommandResult handle(final CommandContext parameters) {
960 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
964 SCLContext sclContext = SCLContext.getCurrent();
965 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
967 Object response = fn.apply(parameters);
968 if(response instanceof CommandResult) {
969 return (CommandResult)response;
972 } catch (Throwable t) {
975 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
980 } catch (Throwable e) {
981 Logger.defaultLogError(e);
982 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
990 public static AbstractEventHandler eventHandler(ReadGraph graph, final Function fn) {
992 return new AbstractEventHandler() {
995 public CommandResult handle(final CommandContext parameters) {
997 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
1003 SCLContext sclContext = SCLContext.getCurrent();
1004 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
1006 Function1<String,String> pf = new FunctionImpl1<String,String>() {
1008 public String apply(String key) {
1009 return parameters.getString(key);
1012 Object response = (String)fn.apply(pf);
1013 if(response instanceof String) {
1014 result = (String)response;
1016 } catch (Throwable t) {
1017 t.printStackTrace();
1019 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1022 return new SuccessResponse(result);
1024 } catch (Throwable e) {
1025 Logger.defaultLogError(e);
1026 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
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);
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);
1044 @SCLValue(type = "ReadGraph -> Resource -> Resource -> ComponentNamingStrategy")
1045 public static ComponentNamingStrategy componentNamingStrategy(ReadGraph graph, Resource converter, Resource context) throws DatabaseException {
1046 return createComponentNamingStrategy(graph);
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>>>() {
1056 public Object apply(ReadGraph p0, Resource p1, String p2) {
1057 return apply(p0, p1, p2);
1059 @SuppressWarnings("unchecked")
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);
1065 return new CaseInsensitiveComponentFunctionNamingStrategy("%s%02d", moduleNameFunction);
1068 public static IExperiment getExperiment(ReadGraph graph, Variable variable) throws DatabaseException {
1069 if (variable == null)
1072 SimulationResource SIMU = SimulationResource.getInstance(graph);
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;
1081 IProject project = Simantics.peekProject();
1082 if (activeRun != null && project != null) {
1083 IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
1085 return expMan.getExperiment(NameUtils.getSafeName(graph, activeRun));
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());
1098 context.putRow(key, list);
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>();
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;
1120 public static String printContext(CommandContext context) {
1121 return context.toString();
1124 @SCLValue(type = "AbstractEventHandler")
1125 public static AbstractEventHandler emptyEvent = new AbstractEventHandler() {
1128 public CommandResult handle(CommandContext context) {
1134 public static String sclStateKey(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1136 String baseURI = base.getURI(graph);
1138 String selfURI = self.getURI(graph);
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;
1144 String relative = Variables.getRelativeRVI(baseURI, stripped);
1146 return Variables.getRVI(relative, ref);
1150 public static Variable sclStateVariable(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1152 String id = sclStateKey(graph, base, self, ref);
1154 Variable sclVar = base.getPossibleChild(graph, "__scl__");
1155 if(sclVar == null) return null;
1157 return sclVar.getPossibleProperty(graph, id);
1161 public static Object sclStateValueOrDefault(ReadGraph graph, Variable base, Variable self, String ref, Object defaultValue) throws DatabaseException {
1163 Variable stateVariable = sclStateVariable(graph, base, self, ref);
1164 if (stateVariable != null) {
1166 return stateVariable.getValue(graph);
1170 String id = sclStateKey(graph, base, self, ref);
1172 SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph) + "/__scl__");
1173 realm.getConnection().setVariable(id, getSCLType(defaultValue), defaultValue);
1175 return defaultValue;
1180 public static void setSclStateValue(WriteGraph graph, Variable base, Variable self, String ref, Object value) throws DatabaseException {
1182 String id = sclStateKey(graph, base, self, ref);
1184 SCLRealm realm = SCLSessionManager.getOrCreateSCLRealm(base.getURI(graph)+"/__scl__");
1185 realm.getConnection().setVariable(id, getSCLType(value), value);
1186 realm.refreshVariablesSync();
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);
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);
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");
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));
1221 public static String documentModelContributionLabel(ReadGraph graph, Variable var) throws DatabaseException {
1222 return var.getName(graph);
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));
1230 public static class ParentExistsRequest extends VariableRead<Boolean> {
1232 public ParentExistsRequest(Variable parent) {
1237 public Boolean perform(ReadGraph graph) throws DatabaseException {
1239 Variable existsProperty = variable.getPossibleProperty(graph, "exists");
1240 if(existsProperty == null) return true;
1242 Boolean exists = existsProperty.getPossibleValue(graph, Bindings.BOOLEAN);
1243 if (exists == null || !exists) return false;
1245 return graph.syncRequest(new ParentExistsRequest(variable.getParent(graph)));
1251 public static class PathExistsRequest extends VariableRead<Boolean> {
1253 public PathExistsRequest(Variable variable) {
1258 public Boolean perform(ReadGraph graph) throws DatabaseException {
1260 Variable widget = variable.getParent(graph);
1262 Boolean exists = widget.getPossiblePropertyValue(graph, "exists");
1263 if (exists == null || !exists) return false;
1265 if (!graph.syncRequest(new ParentExistsRequest(widget.getParent(graph)))) return false;
1267 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1268 Collection <Variable> cps = widget.getProperties(graph, DocumentationResource.URIs.Relations_parentRelation);
1269 for (Variable cp : cps) {
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")) {
1279 Variable parentCp = graph.sync(new UnaryRead<Connection, Variable>(conn) {
1281 public Variable perform(ReadGraph graph) throws DatabaseException {
1282 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1283 Collection<VariableConnectionPointDescriptor> descs = parameter.getConnectionPointDescriptors(graph, null);
1285 for(VariableConnectionPointDescriptor desc : descs) {
1286 if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
1287 return desc.getVariable(graph);
1293 if (parentCp != null) {
1294 Variable parentWidget = parentCp.getParent(graph);
1295 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1302 Resource type = widget.getType(graph);
1303 return graph.isInheritedFrom(type, DOC.Components_ParentlessComponent) ||
1304 (graph.isInheritedFrom(type, DOC.DocumentComponent) && cps.isEmpty());
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));
1313 public static String compileDocumentSCLValueExpression(ReadGraph graph, Variable context) {
1315 ServerSCLValueRequest.validate(graph, context);
1317 } catch (Exception e) {
1318 return resolveIssueMessage(e);
1322 private static String resolveIssueMessage(Exception e) {
1323 if (e instanceof ImportFailureException)
1325 if (e.getCause() != null && e.getCause() instanceof ImportFailureException)
1327 if (e instanceof SCLDatabaseException) {
1328 SCLDatabaseException ee = (SCLDatabaseException) e;
1329 return ee.getMessage();
1331 if (LOGGER.isDebugEnabled())
1332 LOGGER.debug("", e);
1333 return e.getMessage();