Commit b62749ec authored by Vít Kabele's avatar Vít Kabele

RequestDispatcher partially instantiated. Some comments added.

parent 7e27744d
package ch.usi.dag.dislreserver;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import ch.usi.dag.util.logging.Logger;
......@@ -27,6 +18,7 @@ public abstract class DiSLREServer {
//
private static final String PROP_DEBUG = "debug";
@Deprecated
private static final boolean debug = Boolean.getBoolean(PROP_DEBUG);
private static final String PROP_PORT = "dislreserver.port";
......@@ -53,7 +45,9 @@ public abstract class DiSLREServer {
__log.debug ("server started");
__serverStarted ();
run (socket);
ISHVM server = new SHVM (socket, __log, debug);
server.run ();
__log.debug ("server shutting down");
__closeSocket (socket);
......@@ -63,87 +57,7 @@ public abstract class DiSLREServer {
}
private static void run (final ServerSocketChannel socket) {
try {
final SocketChannel clientSocket = socket.accept ();
__log.debug (
"connection from %s", clientSocket.getRemoteAddress ()
);
processRequests (clientSocket.socket ());
clientSocket.close ();
} catch (final ClosedByInterruptException cbie) {
//
// The server was interrupted, we are shutting down.
//
} catch (final IOException ioe) {
//
// Communication error -- just log a message here.
//
__log.error ("error accepting a connection: %s", ioe.getMessage ());
}
}
private static void processRequests (final Socket sock) {
try {
final DataInputStream is = new DataInputStream (
new BufferedInputStream (sock.getInputStream ()));
final DataOutputStream os = new DataOutputStream (
new BufferedOutputStream (sock.getOutputStream ()));
REQUEST_LOOP: while (true) {
final byte requestNo = is.readByte ();
if (RequestDispatcher.dispatch (requestNo, is, os, debug)) {
break REQUEST_LOOP;
}
}
} catch (final Exception e) {
__logError (e);
}
}
private static void __logError (final Throwable throwable) {
if (throwable instanceof DiSLREServerException) {
__logNestedErrors (throwable);
if (__log.debugIsLoggable ()) {
__log.debug (__getFullMessage (throwable));
}
} else {
// some other exception
__log.error ("fatal error: %s", __getFullMessage (throwable));
}
}
private static void __logNestedErrors (final Throwable throwable) {
String prefix = "server error: ";
Throwable current = throwable;
do {
final String message = throwable.getMessage ();
if (message != null) {
__log.error ("%s%s", prefix, message);
}
prefix = "\t";
current = throwable.getCause ();
} while (current != null);
}
private static String __getFullMessage (final Throwable t) {
final StringWriter result = new StringWriter ();
t.printStackTrace (new PrintWriter (result));
return result.toString ();
}
//
......@@ -195,12 +109,24 @@ public abstract class DiSLREServer {
}
/**
* Returns reference to the file named by the property provided
* in parameter name.
*
* @param name Name of the property
* @return file reference or null while non-existing property
*/
private static File __getFileProperty (final String name) {
final String value = System.getProperty (name, "").trim ();
return value.isEmpty () ? null : new File (value);
}
/**
* Close the socket
*
* @param socket
*/
private static void __closeSocket (final Closeable socket) {
try {
socket.close ();
......
/**
* Logging methods extracted from DiSLREServer class
*
* Author: Vit Kabele <vit@kabele.me>
* Created on the 21/02/2019
*/
package ch.usi.dag.dislreserver;
import ch.usi.dag.util.logging.Logger;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* Logging methods extracted from DiSLREServer class
*/
abstract class Log {
private static String __getFullMessage (final Throwable t) {
final StringWriter result = new StringWriter ();
t.printStackTrace (new PrintWriter (result));
return result.toString ();
}
private static void __logNestedErrors (final Throwable throwable, final Logger __log) {
String prefix = "server error: ";
Throwable current = throwable;
do {
final String message = throwable.getMessage ();
if (message != null) {
__log.error ("%s%s", prefix, message);
}
prefix = "\t";
current = throwable.getCause ();
} while (current != null);
}
static void __logError (final Throwable throwable, final Logger __log) {
if (throwable instanceof DiSLREServerException) {
__logNestedErrors (throwable, __log);
if (__log.debugIsLoggable ()) {
__log.debug (Log.__getFullMessage (throwable));
}
} else {
// some other exception
__log.error ("fatal error: %s", Log.__getFullMessage (throwable));
}
}
}
/**
* ISHVM implementation
*
* Author: Vit Kabele <vit@kabele.me>
* Created on the 21/02/2019
*/
package ch.usi.dag.dislreserver;
import java.io.*;
import java.net.Socket;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import ch.usi.dag.util.logging.Logger;
/**
* Implementation of ISHVM.
*
* This class should represent the one re-usable class that will represent
* i.e. one analysis session. All the needed data including reflective information
* should be available in its instance.
*/
public class SHVM implements ISHVM {
/**
* Socket for communication with client
*/
private final ServerSocketChannel __socket;
/**
* Logger instance
*/
private final Logger __log;
/**
* Debug flag
*/
@Deprecated
private final boolean __debug;
/**
* Request dispatcher
*/
private final RequestDispatcher __requestDispatcher;
/**
* Public constructor
*
* @param socket
* @param logger
* @param debug
*/
SHVM (
final ServerSocketChannel socket,
final Logger logger,
final boolean debug
) {
__socket = socket;
__log = logger;
__debug = debug;
__requestDispatcher = new RequestDispatcher ();
}
@Override
public void run () {
try {
final SocketChannel clientSocket = __socket.accept ();
__log.debug (
"connection from %s", clientSocket.getRemoteAddress ()
);
processRequests (clientSocket.socket ());
clientSocket.close ();
} catch (final ClosedByInterruptException cbie) {
//
// The server was interrupted, we are shutting down.
//
} catch (final IOException ioe) {
//
// Communication error -- just log a message here.
//
__log.error ("error accepting a connection: %s", ioe.getMessage ());
}
}
private void processRequests (final Socket sock) {
try {
final DataInputStream is = new DataInputStream (
new BufferedInputStream (sock.getInputStream ()));
final DataOutputStream os = new DataOutputStream (
new BufferedOutputStream (sock.getOutputStream ()));
while (true) {
final byte requestNo = is.readByte ();
if (__requestDispatcher.dispatch (requestNo, is, os, __debug)) {
break;
}
}
} catch (final Exception e) {
Log.__logError (e, __log);
}
}
}
......@@ -12,6 +12,11 @@ import ch.usi.dag.dislreserver.shadow.ShadowObject;
import ch.usi.dag.dislreserver.shadow.ShadowObjectTable;
/**
* AnalysisHandler class
*
* Takes care of handling the requests to analysis invocations.
*/
public final class AnalysisHandler implements RequestHandler {
private AnalysisDispatcher dispatcher = new AnalysisDispatcher ();
......@@ -20,6 +25,7 @@ public final class AnalysisHandler implements RequestHandler {
return dispatcher;
}
@Override
public void handle (
final DataInputStream is, final DataOutputStream os, final boolean debug
) throws DiSLREServerException {
......@@ -195,14 +201,15 @@ public final class AnalysisHandler implements RequestHandler {
));
}
public void threadEnded(long threadId) {
void threadEnded(long threadId) {
dispatcher.threadEndedEvent(threadId);
}
public void objectsFreed(long[] objFreeIDs) {
void objectsFreed(long[] objFreeIDs) {
dispatcher.objectsFreedEvent(objFreeIDs);
}
@Override
public void exit() {
dispatcher.exit();
}
......
......@@ -10,13 +10,26 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* AnalysisResolver class
*
* Takes care of resolving the analysis methods,
* registering their IDs and finding them back.
*
* Each SHVM session should have own instance because of
* different analysis might want to register methods with
* the same name.
*
*/
public final class AnalysisResolver {
private static final String METHOD_DELIM = ".";
private static final Map <Short, AnalysisMethodHolder>
methodMap = new HashMap <Short, AnalysisMethodHolder> ();
/**
* Cache the analysis classes
*/
private static final Map <String, RemoteAnalysis>
analysisMap = new HashMap <String, RemoteAnalysis> ();
......@@ -26,6 +39,9 @@ public final class AnalysisResolver {
//
/**
* Holds the instance of analysis and the analysis method.
*/
public static final class AnalysisMethodHolder {
private final RemoteAnalysis analysisInstance;
private final Method analysisMethod;
......@@ -48,8 +64,20 @@ public final class AnalysisResolver {
//
private static AnalysisMethodHolder resolveMethod (String methodStr
) throws DiSLREServerException {
/**
* Resolve the analysis method by name.
*
* The resulting instances are retreived via native reflection
* and the repeating calls are cached in analysisMap.
*
* @param methodStr Fully qualified name of the method (containing class name)
* @return
* @throws DiSLREServerException
*/
private static AnalysisMethodHolder resolveMethod (
String methodStr
) throws DiSLREServerException
{
try {
int classNameEnd = methodStr.lastIndexOf (METHOD_DELIM);
......@@ -85,9 +113,19 @@ public final class AnalysisResolver {
}
}
/**
* Obtains the instance of RemoteAnalysis class and extracts the method with given name.
*
* @param analysis
* @param methodName
* @return Method
* @throws DiSLREServerException
*/
private static Method __getAnalysisMethod (
final RemoteAnalysis analysis, final String methodName
) throws DiSLREServerException {
) throws DiSLREServerException
{
final Class <?> analysisClass = analysis.getClass ();
final List <Method> methods = new ArrayList <Method> ();
......@@ -118,8 +156,16 @@ public final class AnalysisResolver {
}
/**
* Return the (previously registered) method mapped to the methodId
*
* @param methodId Method Id
* @return Method handler
* @throws DiSLREServerException
*/
static AnalysisMethodHolder getMethod (final short methodId)
throws DiSLREServerException {
throws DiSLREServerException
{
AnalysisMethodHolder result = methodMap.get (methodId);
if (result == null) {
throw new DiSLREServerFatalException ("Unknown method id: "+ methodId);
......@@ -129,13 +175,26 @@ public final class AnalysisResolver {
}
/**
* Public api of the class. Used to register new methods and their IDs to the analysis.
*
* @param methodId
* @param methodString
* @throws DiSLREServerException
*/
public static void registerMethodId (
final short methodId, String methodString
) throws DiSLREServerException {
) throws DiSLREServerException
{
methodMap.put(methodId, resolveMethod(methodString));
}
/**
* Getter for the set of all analyses.
*
* @return Set of all analyses
*/
public static Set <RemoteAnalysis> getAllAnalyses () {
return analysisSet;
}
......
......@@ -6,6 +6,13 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
/**
* CloseHandler class.
*
* Handle the request signalizing the end of analysis.
* This includes calling "destructor" on all registered event handlers
* and on all analyses.
*/
public final class CloseHandler implements RequestHandler {
@Override
......
......@@ -7,6 +7,12 @@ import java.io.DataOutputStream;
import java.io.IOException;
/**
* NewClassHandler class
*
* Handle the request signalizing that a new class has been loaded
* to the observed virtual machine.
*/
public class NewClassHandler implements RequestHandler {
@Override
......
......@@ -5,39 +5,48 @@ import java.io.DataOutputStream;
import java.io.IOException;
/**
* ObjectFreeHandler class
*
* Handle the request notifying about the object free event in observed VM
*/
public class ObjectFreeHandler implements RequestHandler {
final AnalysisHandler analysisHandler;
private final AnalysisHandler analysisHandler;
public ObjectFreeHandler(AnalysisHandler anlHndl) {
ObjectFreeHandler (AnalysisHandler anlHndl) {
analysisHandler = anlHndl;
}
public void handle(DataInputStream is, DataOutputStream os, boolean debug)
throws DiSLREServerException {
@Override
public void handle (
DataInputStream is,
DataOutputStream os,
boolean debug
) throws DiSLREServerException
{
try {
int freeCount = is.readInt();
int freeCount = is.readInt ();
long[] objFreeIDs = new long[freeCount];
for(int i = 0; i < freeCount; ++i) {
for (int i = 0; i < freeCount; ++i) {
long netref = is.readLong();
long netref = is.readLong ();
objFreeIDs[i] = netref;
}
analysisHandler.objectsFreed(objFreeIDs);
analysisHandler.objectsFreed (objFreeIDs);
} catch (IOException e) {
throw new DiSLREServerException(e);
throw new DiSLREServerException (e);
}
}
public void exit() {
}
@Override
public void exit () {}
}
......@@ -5,10 +5,18 @@ import java.io.DataOutputStream;
import java.io.IOException;
/**
* Register analysis method handler
*/
public final class RegAnalysisHandler implements RequestHandler {
public void handle(final DataInputStream is, final DataOutputStream os,
final boolean debug) throws DiSLREServerException {
@Override
public void handle(
final DataInputStream is,
final DataOutputStream os,
final boolean debug
) throws DiSLREServerException
{
try {
final short methodId = is.readShort();
String methodString = is.readUTF();
......@@ -27,8 +35,7 @@ public final class RegAnalysisHandler implements RequestHandler {
}
}
public void exit() {
}
@Override
public void exit() {}
}
......@@ -7,6 +7,9 @@ import java.io.DataOutputStream;
import java.io.IOException;
/**
* Handle the thread info message.
*/
public class ThreadInfoHandler implements RequestHandler {
@Override
......
......@@ -54,6 +54,10 @@ public final class RequestDispatcher {
__dispatchTable = __createDispatchTable (requestMap);
}
/**
* Constructor
*/
RequestDispatcher() {}
private static RequestHandler [] __createDispatchTable (
final Map <Byte, RequestHandler> requestMap
......@@ -72,7 +76,7 @@ public final class RequestDispatcher {
//
public static boolean dispatch (
public boolean dispatch (
final byte requestId, final DataInputStream is,
final DataOutputStream os, boolean debug
) throws DiSLREServerException {
......@@ -100,7 +104,7 @@ public final class RequestDispatcher {
}
public static Iterable <RequestHandler> getAllHandlers () {
static Iterable <RequestHandler> getAllHandlers () {
return __handlers;
}
......
This is the public api of DiSL Reserver, it should contain
interfaces and data types used to call public server methods
/**
* Public interface specifying the public API of REServer
*
* Author: Vit Kabele <vit@kabele.me>
* Created on the 21/02/2019
*/
package ch.usi.dag.dislreserver;
/**
* Public interface specifying the public API of REServer
*/
public interface ISHVM {
/**
* Run the server and start processing requests.
*/
void run();
}
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