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