--- /dev/null
+package org.simantics.scl.commands.internal;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.WriteResultRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.procedure.Procedure;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.scl.commands.Command;\r
+import org.simantics.scl.commands.internal.checker.Checker;\r
+import org.simantics.scl.commands.internal.serialization.CommandSerializer;\r
+import org.simantics.scl.commands.internal.serialization.CommandSerializerFactory;\r
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;\r
+import org.simantics.scl.compiler.top.ValueNotFound;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+import org.simantics.scl.compiler.types.util.MultiFunction;\r
+import org.simantics.scl.osgi.SCLOsgi;\r
+import org.simantics.scl.runtime.SCLContext;\r
+import org.simantics.scl.runtime.function.Function;\r
+import org.simantics.utils.logging.TimeLogger;\r
+\r
+/**\r
+ * Default command implementation\r
+ * \r
+ * @author Hannu Niemistö\r
+ */\r
+@SuppressWarnings({"rawtypes", "restriction"})\r
+public class CommandImpl implements Command {\r
+\r
+ String name;\r
+ Function command;\r
+ Type[] parameterTypes;\r
+ CommandSerializer serializer; \r
+ Checker checker;\r
+ \r
+ public CommandImpl(String name, Function command, Type[] parameterTypes,\r
+ CommandSerializer serializer, Checker checker) {\r
+ this.name = name;\r
+ this.command = command;\r
+ this.parameterTypes = parameterTypes;\r
+ this.serializer = serializer;\r
+ this.checker = checker;\r
+ }\r
+ \r
+ private class CheckRequest implements Read<Boolean> {\r
+ Object[] parameters;\r
+ \r
+ public CheckRequest(Object[] parameters) {\r
+ this.parameters = parameters;\r
+ }\r
+\r
+ @Override\r
+ public Boolean perform(ReadGraph graph) throws DatabaseException {\r
+ SCLContext sclContext = SCLContext.getCurrent();\r
+ Object oldGraph = sclContext.put("graph", graph);\r
+ boolean result = checker.check(parameters);\r
+ sclContext.put("graph", oldGraph);\r
+ return result;\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public boolean check(RequestProcessor processor, Resource model,\r
+ Object... parameters) throws DatabaseException {\r
+ CheckRequest request = new CheckRequest(parameters);\r
+ if(processor instanceof ReadGraph)\r
+ return request.perform((ReadGraph)processor);\r
+ else\r
+ return processor.syncRequest(request);\r
+ }\r
+\r
+ private static boolean serializationErrorAlreadySeen = false;\r
+ \r
+ private class CommitRequest extends WriteResultRequest<Object> {\r
+ Resource model;\r
+ Object[] parameters;\r
+ \r
+ public CommitRequest(Resource model, Object[] parameters) {\r
+ this.model = model;\r
+ this.parameters = parameters;\r
+ }\r
+\r
+ @Override\r
+ public Object perform(WriteGraph graph) throws DatabaseException {\r
+ SCLContext sclContext = SCLContext.getCurrent();\r
+ Object oldGraph = sclContext.put("graph", graph);\r
+ // Serialize command first\r
+ try {\r
+ serializer.serialize(graph, model, parameters);\r
+ } catch(Exception e) {\r
+ if(!serializationErrorAlreadySeen) {\r
+ e.printStackTrace();\r
+ serializationErrorAlreadySeen = true;\r
+ }\r
+ } \r
+ \r
+ // Then execute (otherwise target of the command might not exist anymore)\r
+ try {\r
+ return command.applyArray(parameters);\r
+ } finally {\r
+ sclContext.put("graph", oldGraph);\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ @Override\r
+ public Object execute(RequestProcessor processor, Resource model, Object ... parameters) throws DatabaseException {\r
+ if(parameters.length != parameterTypes.length)\r
+ throw new IllegalArgumentException("Wrong number of parameters given (" + parameters.length + ") expected " +\r
+ parameterTypes.length + " parameters.");\r
+ CommitRequest request = new CommitRequest(model, parameters);\r
+ try {\r
+ if(processor instanceof WriteGraph)\r
+ return request.perform((WriteGraph)processor);\r
+ else\r
+ return processor.syncRequest(request);\r
+ } finally {\r
+ TimeLogger.log("Executed command " + name);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void asyncExecute(RequestProcessor processor, Resource model,\r
+ Object[] parameters, Procedure<Object> procedure) {\r
+ processor.asyncRequest(new CommitRequest(model, parameters), procedure);\r
+ }\r
+\r
+ public static Command create(ReadGraph graph, String name) {\r
+ Object oldGraph = SCLContext.getCurrent().put("graph", graph);\r
+ try {\r
+ SCLValue commandRef = SCLOsgi.MODULE_REPOSITORY.getValueRef(name);\r
+ MultiFunction mfun = Types.matchFunction(commandRef.getType());\r
+ Type[] parameterTypes = mfun.parameterTypes;\r
+ Function command = (Function)SCLOsgi.MODULE_REPOSITORY.getValue(name);\r
+ CommandSerializer serializer = CommandSerializerFactory.create(name, parameterTypes);\r
+ Checker checker = Checker.create(name + "_check");\r
+ return new CommandImpl(name, command, parameterTypes, serializer, checker);\r
+ } catch(ValueNotFound e) {\r
+ e.printStackTrace();\r
+ return new ErrorCommand(name);\r
+ } finally {\r
+ SCLContext.getCurrent().put("graph", oldGraph);\r
+ }\r
+ }\r
+}\r