com.tinkerpop.rexster.protocol.server.ScriptServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rexster-protocol Show documentation
Show all versions of rexster-protocol Show documentation
RexPro is a binary protocol for Rexster graph server.
package com.tinkerpop.rexster.protocol.server;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.TransactionalGraph;
import com.tinkerpop.rexster.protocol.EngineController;
import com.tinkerpop.rexster.protocol.msg.ErrorResponseMessage;
import com.tinkerpop.rexster.protocol.msg.MessageTokens;
import com.tinkerpop.rexster.protocol.msg.MessageUtil;
import com.tinkerpop.rexster.protocol.msg.RexProMessage;
import com.tinkerpop.rexster.protocol.msg.ScriptRequestMessage;
import com.tinkerpop.rexster.protocol.session.AbstractRexProSession;
import com.tinkerpop.rexster.protocol.session.RexProSessions;
import com.tinkerpop.rexster.server.RexsterApplication;
import org.apache.log4j.Logger;
import javax.script.Bindings;
import javax.script.ScriptException;
import java.io.IOException;
/**
* @author Blake Eggleston (bdeggleston.github.com)
*/
public class ScriptServer {
private static final Logger logger = Logger.getLogger(ScriptServer.class);
private static final EngineController engineController = EngineController.getInstance();
private final RexsterApplication rexsterApplication;
private final Timer scriptTimer;
/**
* A count of successful execution of scripts. Counts even if a write back to the stream fails.
*/
private final Counter successfulExecutions;
/**
* A count of failed script executions. Not the same as a failed request.
*/
private final Counter failedExecutions;
public ScriptServer(final RexsterApplication rexsterApplication) {
this.rexsterApplication = rexsterApplication;
final MetricRegistry metricRegistry = this.rexsterApplication.getMetricRegistry();
this.scriptTimer = metricRegistry.timer(MetricRegistry.name("rexpro", "script-engine"));
this.successfulExecutions = metricRegistry.counter(MetricRegistry.name("rexpro", "script-engine", "success"));
this.failedExecutions = metricRegistry.counter(MetricRegistry.name("rexpro", "script-engine", "fail"));
}
public void handleRequest(ScriptRequestMessage message, RexProRequest request) throws IOException {
try {
final AbstractRexProSession session;
Graph graph = null;
message.validateMetaData();
if (message.metaGetInSession()) {
if (message.Session == null) {
logger.error("no session key on message");
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request,
RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.INVALID_SESSION_ERROR,
"There was no session key on the message, set the meta field 'inSession' to false if you want to execute sessionless requests"
)
);
}
//session script request
session = RexProSessions.getSession(message.sessionAsUUID().toString());
// validate session and channel
if (sessionDoesNotExist(request, message, session)) return;
graph = session.getGraphObj();
// catch any graph redefinition attempts
if (graphIsRedefined(request, message, message, graph)) return;
} else {
session = new EmptySession(rexsterApplication);
}
Bindings bindings = message.getBindings();
// add the graph object to the bindings
if (message.metaGetGraphName() != null) {
graph = rexsterApplication.getGraph(message.metaGetGraphName());
bindings.put(message.metaGetGraphObjName(), graph);
if (graph == null) {
// graph config problem
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request, RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.GRAPH_CONFIG_ERROR,
"the graph '" + message.metaGetGraphName() + "' was not found by Rexster"
)
);
return;
}
}
final Timer.Context timer = scriptTimer.time();
try {
// execute script
session.evaluate(
message.Script,
message.LanguageName,
bindings,
message.metaGetIsolate(),
message.metaGetTransaction(),
graph,
request
);
successfulExecutions.inc();
} catch (Exception ex) {
// rollback transaction
if (message.metaGetTransaction()) {
tryRollbackTransaction(graph);
}
failedExecutions.inc();
throw ex;
} finally {
timer.stop();
}
} catch (ScriptException se) {
logger.warn("Could not process script [" + message.Script + "] for language ["
+ message.LanguageName + "] on session [" + message.Session
+ "] and request [" + message.Request + "]");
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request, RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.SCRIPT_FAILURE_ERROR,
String.format(
MessageTokens.ERROR_IN_SCRIPT_PROCESSING,
message.LanguageName,
se.getMessage()
)
)
);
} catch (Exception e) {
logger.error(e);
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request,
RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.SCRIPT_FAILURE_ERROR,
String.format(
MessageTokens.ERROR_IN_SCRIPT_PROCESSING,
message.LanguageName,
e.toString()
)
)
);
}
}
public static void tryRollbackTransaction(final Graph graph) {
if (graph == null) return;
if (graph.getFeatures().supportsTransactions && graph instanceof TransactionalGraph) {
((TransactionalGraph) graph).stopTransaction(TransactionalGraph.Conclusion.FAILURE);
}
}
public static void tryCommitTransaction(final Graph graph) {
if (graph == null) return;
if (graph.getFeatures().supportsTransactions && graph instanceof TransactionalGraph) {
((TransactionalGraph) graph).stopTransaction(TransactionalGraph.Conclusion.SUCCESS);
}
}
/**
* The graph cannot be redefined within a session.
*/
private static boolean graphIsRedefined(final RexProRequest request, final RexProMessage message,
final ScriptRequestMessage specificMessage, final Graph graph) throws IOException {
if (specificMessage.metaGetGraphName() != null && graph != null) {
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request, RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.GRAPH_CONFIG_ERROR,
MessageTokens.ERROR_GRAPH_REDEFINITION
)
);
return true;
}
return false;
}
/**
* The session has to be found for script to be executed.
*/
private static boolean sessionDoesNotExist(final RexProRequest request, final RexProMessage message, final AbstractRexProSession session) throws IOException {
if (session == null) {
// the message is assigned a session that does not exist on the server
request.writeResponseMessage(
MessageUtil.createErrorResponse(
message.Request,
RexProMessage.EMPTY_SESSION_AS_BYTES,
ErrorResponseMessage.INVALID_SESSION_ERROR,
MessageTokens.ERROR_SESSION_INVALID
)
);
return true;
}
return false;
}
/**
* Simplified session class that executes scripts immediately
*/
private class EmptySession extends AbstractRexProSession {
private EmptySession(RexsterApplication rexsterApplication) {
super(rexsterApplication);
}
protected void execute(Evaluator evaluator) throws ScriptException {
try {
evaluator.call();
} catch (Exception e) {
throw new ScriptException(e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy