Commit 2dcd506f authored by Lubomir Bulej's avatar Lubomir Bulej

Clean up request dispatching a little bit

parent bb15cd61
......@@ -20,40 +20,41 @@ import ch.usi.dag.shvm.SHVMImpl;
final class RequestDispatcher {
/**
* Pure static class.
*/
private RequestDispatcher() {}
/**
* Pass the messages to appropriate handlers and return {@link ServerMessage} containing
* the reply. When null is returned, then no reply will be sent.
* Dispatches the message to the appropriate handler. Returns a response to
* be sent to the client (including errors occurring during request
* processing) or {@code null} if no response should be sent.
*
* @param message
* @param context
*
* @return
* @throws ServerRuntimeException When a serious error during occurs during server runtime.
* @return {@link ServerMessage} with response to the request or
* {@code null} if no response is to be sent.
* @throws ServerRuntimeException
* If an internal server error occurs.
*/
static ServerMessage dispatchMessage(
final ClientMessage message,
final Server.Context context
) throws ServerRuntimeException
{
ServerMessage serverMessage = null;
final ServerMessage.Builder builder = ServerMessage.newBuilder().setResponseId(message.getRequestId());
static ServerMessage dispatchMessage (
final ClientMessage message, final Server.Context context
) throws ServerRuntimeException {
final ServerMessage.Builder builder = ServerMessage.newBuilder ()
.setResponseId (message.getRequestId ());
try {
switch (message.getRequestCase()) {
switch (message.getRequestCase ()) {
case SESSION_INIT_REQUEST:
serverMessage = handleSessionInit(context, message.getSessionInitRequest(), builder);
break;
return handleSessionInit (
message.getSessionInitRequest (), context, builder
);
case CLOSE_CONNECTION:
final Integer sessionID = message.getSessionId();
handleCloseConnection(context, sessionID);
break;
// No response is returned when closing connection.
handleCloseConnection (message.getSessionId (), context);
return null;
case INSTRUMENTATION_DELIVERY:
case INSTRUMENT_CLASS_REQUEST:
serverMessage = InstrumentationRequestDispatcher.dispatchMessage(context, message, builder);
break;
return InstrumentationRequestDispatcher.dispatchMessage (
message, context, builder
);
case REGISTER_ANALYSIS:
case NEW_CLASS:
case ANALYZE:
......@@ -62,75 +63,83 @@ final class RequestDispatcher {
case STRING_INFO:
case THREAD_END:
case CLASS_INFO:
serverMessage = AnalysisRequestDispatcher.dispatchMessage(context, message);
break;
// Analysis messages don't provide responses.
AnalysisRequestDispatcher.dispatchMessage (message, context);
return null;
case REQUEST_NOT_SET:
default:
throw new ServerRuntimeException(
String.format("Cannot handle request case %s", message.getRequestCase().name())
// Internal error. Should be handled upstream.
throw new ServerRuntimeException (
"unable to handle request %s", message.getRequestCase ()
);
}
} catch (final RequestErrorException e) {
context.log.info("Sending error message to the client: [%s]", e.getLocalizedMessage());
serverMessage = builder
.setError(
__createErrorMessage(e.getMessage())
)
.build();
} catch (final RequestErrorException e) {
//
// Error while processing the request: notify the client.
// This is a "valid" outcome, upstream code does not need to know.
//
context.log.error ("failed to process request: %s", e.getMessage ());
return builder.setError (
Main.Error.newBuilder ().setMessage (e.getMessage ()).build ()
).build ();
}
return serverMessage;
}
/**
* Register the session in the {@link SessionManager} instance and return {@link ServerMessage}
* acquiring the creation of session and containing the session id.
* Creates a new session and prepares a response for the client. The session
* is initialized with DiSL and/or Shadow VM runtime depending on what the
* client requested.
*
* @param context
* @param request
* @param context
* @return
*/
private static ServerMessage handleSessionInit(
final Server.Context context,
private static ServerMessage handleSessionInit (
final SessionInitRequest request,
final Server.Context context,
final ServerMessage.Builder builder
) throws RequestErrorException
{
final Session session = context.sessionManager.createSession();
) throws RequestErrorException {
final Session session = context.sessionManager.createSession ();
// Client requires the ShadowVM functionality
session.setShadowVMRequested(request.getRequireShvm());
if (request.getRequireShvm()) {
final boolean analysisRequired = request.getRequireShvm();
session.setShadowVMRequested (analysisRequired);
if (analysisRequired) {
// Server is able to provide such functionality
if (context.isShvm) {
session.setShadowVM(new SHVMImpl(context.log));
session.setShadowVM (new SHVMImpl (context.log));
} else {
context.log.info("Client requested unsupported functionality (analysis). "
+ "To enable it, run the server with the --analysis option.");
throw new RequestErrorException("Server does not provide analysis services");
}
context.log.info (
"Client requested analysis functionality. "+
"To enable it, run the server with the --analysis option."
);
throw new RequestErrorException (
"Server does not provide analysis services"
);
}
}
// Client requires the DiSL functionality
session.setDiSLRequested(request.getRequireDisl());
if (request.getRequireDisl() && !context.isDisl) {
context.log.info("Client requested unsupported functionality (instrumentation). "
+ "To enable it, run the server with the --instrumentation option.");
throw new RequestErrorException("Server does not provide instrumentation services");
final boolean instrumentationRequired = request.getRequireDisl();
session.setDiSLRequested (instrumentationRequired);
if (instrumentationRequired && !context.isDisl) {
context.log.info(
"Client requested instrumentation functionality. "+
"To enable it, run the server with the --instrumentation option."
);
throw new RequestErrorException (
"Server does not provide instrumentation services"
);
}
return builder
.setSessionInitResponse(
SessionInitResponse
.newBuilder()
.setSessionId(session.id())
.build()
).build();
return builder.setSessionInitResponse (
SessionInitResponse.newBuilder ().setSessionId (session.id ()).build ()
).build ();
}
......@@ -138,35 +147,18 @@ final class RequestDispatcher {
* Handles the request to close the session. Requests the session manager to
* terminate the session and remove it from its registry.
*
* Note that the instances in {@link Server.Context} might be null, when the functionality is
* not required by the client.
*
* @param context
* @param sessionId
* @return
* @throws RequestErrorException
* @param context
*/
private static ServerMessage handleCloseConnection (
final Server.Context context, final int sessionId
private static void handleCloseConnection (
final int sessionId, final Server.Context context
) throws RequestErrorException {
context.log.debug ("Closing session %d", sessionId);
context.log.debug ("closing session %d", sessionId);
context.sessionManager.terminateSession (sessionId);
return null;
}
//
/**
* Create the protobuf error message that will be sent to the client in case of failure or
* wrong request.
*
* @param message The message text.
* @return Error message that will be sent to the client.
*/
private static Main.Error __createErrorMessage(final String message)
{
return Main.Error.newBuilder()
.setMessage(message)
.build();
}
private RequestDispatcher () { /* No instances to be made. */ }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment