Commit 3891ee98 authored by Lubomir Bulej's avatar Lubomir Bulej

DiSL-RE agent: include length of marshalled argument data in the analysis invocation request

DiSL-RE agent: various typo fixes and cleanups
DiSL-RE server: check that length of unmarshalled argument data matches length of marshalled data
DiSL-RE server: fail if more than one or no analysis method matches analysis method being registered
DiSL-RE server: various cleanups
parent a251e261
......@@ -144,6 +144,7 @@ struct tldata {
buffer * command_buff;
jint analysis_count;
size_t analysis_count_pos;
size_t args_length_pos;
};
......@@ -428,17 +429,21 @@ static void pack_class(JNIEnv * jni_env, buffer * buff, buffer * cmd_buff,
pack_int(buff, NULL_NET_REF);
}
static void buff_put_int(buffer * buff, size_t buff_pos, jint to_put) {
static void buff_put_short(buffer * buff, size_t buff_pos, jshort to_put) {
// put the short at the position in network order
jshort nts = htons(to_put);
buffer_fill_at_pos(buff, buff_pos, &nts, sizeof(jshort));
}
jint nts = htonl(to_put);
// put the long on the position in a proper format
static void buff_put_int(buffer * buff, size_t buff_pos, jint to_put) {
// put the int at the position in network order
jint nts = htonl(to_put);
buffer_fill_at_pos(buff, buff_pos, &nts, sizeof(jint));
}
static void buff_put_long(buffer * buff, size_t buff_pos, jlong to_put) {
// put the long on the position in a proper format
// put the long at the position in network order
jlong nts = htobe64(to_put);
buffer_fill_at_pos(buff, buff_pos, &nts, sizeof(jlong));
}
......@@ -517,6 +522,23 @@ static jlong next_thread_id () {
return result;
}
static size_t createAnalysisRequestHeader (
buffer * buff, jshort analysis_method_id
) {
// analysis method id
pack_short(buff, analysis_method_id);
// position of the short indicating the length of marshalled arguments
size_t pos = buffer_filled(buff);
// initial value of the length of the marshalled arguments
pack_short(buff, 0xBAAD);
return pos;
}
void analysis_start_buff(
JNIEnv * jni_env, jshort analysis_method_id, jbyte ordering_id,
struct tldata * tld
......@@ -543,16 +565,17 @@ void analysis_start_buff(
tld->to_buff_id = ordering_id;
// analysis method desc
pack_short(tld->analysis_buff, analysis_method_id);
// create request header, keep track of the position
// of the length of marshalled arguments
tld->args_length_pos = createAnalysisRequestHeader(tld->analysis_buff, analysis_method_id);
#ifdef DEBUG
printf("Analysis (buffer) start exit (thread %ld)\n", tld_get()->id);
#endif
}
static size_t createAnalysisMsg(buffer * buff, jlong id) {
static size_t createAnalysisMsg(buffer * buff, jlong id) {
// create analysis message
// analysis msg
......@@ -564,12 +587,14 @@ static size_t createAnalysisMsg(buffer * buff, jlong id) {
// get pointer to the location where count of requests will stored
size_t pos = buffer_filled(buff);
// space initialization
pack_int(buff, 0);
// request count space initialization
pack_int(buff, 0xBAADF00D);
return pos;
}
static void analysis_start(
JNIEnv * jni_env, jshort analysis_method_id,
struct tldata * tld
......@@ -590,15 +615,16 @@ static void analysis_start(
tld->analysis_buff = tld->pb->analysis_buff;
tld->command_buff = tld->pb->command_buff;
// determines, how many analysis requests are send in one message
// determines, how many analysis requests are sent in one message
tld->analysis_count = 0;
// crate analysis message
// create analysis message
tld->analysis_count_pos = createAnalysisMsg(tld->analysis_buff, tld->id);
}
// analysis method desc
pack_short(tld->analysis_buff, analysis_method_id);
// create request header, keep track of the position
// of the length of marshalled arguments
tld->args_length_pos = createAnalysisRequestHeader(tld->analysis_buff, analysis_method_id);
#ifdef DEBUG
printf("Analysis start exit (thread %ld)\n", tld_get()->id);
......@@ -652,10 +678,10 @@ static void analysis_end_buff(struct tldata * tld) {
// set owner_id as t_buffid
tobs->pb->owner_id = tld->to_buff_id;
// determines, how many analysis requests are send in one message
// determines, how many analysis requests are sent in one message
tobs->analysis_count = 0;
// crate analysis message
// create analysis message
tobs->analysis_count_pos = createAnalysisMsg(
tobs->pb->analysis_buff, tld->to_buff_id);
}
......@@ -721,6 +747,10 @@ static void analysis_end_buff(struct tldata * tld) {
}
static void analysis_end(struct tldata * tld) {
// update the length of the marshalled arguments
jshort args_length = buffer_filled(tld->analysis_buff) - tld->args_length_pos - sizeof (jshort);
buff_put_short(tld->analysis_buff, tld->args_length_pos, args_length);
// this method is also called for end of analysis for totally ordered API
if(tld->to_buff_id != INVALID_BUFF_ID) {
analysis_end_buff(tld);
......@@ -742,7 +772,6 @@ static void analysis_end(struct tldata * tld) {
// send only when the method count is reached
if(tld->analysis_count >= ANALYSIS_COUNT) {
// invalidate buffer pointers
tld->analysis_buff = NULL;
tld->command_buff = NULL;
......
......@@ -28,27 +28,44 @@ public final class AnalysisHandler implements RequestHandler {
try {
// get net reference for the thread
long orderingID = is.readLong();
// read and create method invocations
int numberOfMethods = is.readInt();
long orderingID = is.readLong ();
// read and create method invocations
final int invocationCount = is.readInt ();
if (invocationCount < 0) {
throw new DiSLREServerException (String.format (
"invalid number of analysis invocation requests: %d",
invocationCount
));
}
List<AnalysisInvocation> invocations
= new LinkedList<AnalysisInvocation>();
List <AnalysisInvocation> invocations = __unmarshalInvocations (
invocationCount, is, debug
);
for(int i = 0; i < numberOfMethods; ++i) {
invocations.add(createInvocation(is, debug));
}
dispatcher.addTask (orderingID, invocations);
dispatcher.addTask(orderingID, invocations);
} catch (final IOException ioe) {
throw new DiSLREServerException(ioe);
}
catch (IOException e) {
throw new DiSLREServerException(e);
}
private List <AnalysisInvocation> __unmarshalInvocations (
final int invocationCount, final DataInputStream is, final boolean debug
) throws DiSLREServerException {
final List <AnalysisInvocation> result =
new LinkedList <AnalysisInvocation> ();
for (int i = 0; i < invocationCount; ++i) {
result.add (__unmarshalInvocation (is, debug));
}
return result;
}
public AnalysisInvocation createInvocation (
private AnalysisInvocation __unmarshalInvocation (
final DataInputStream is, final boolean debug
) throws DiSLREServerException {
try {
......@@ -60,13 +77,33 @@ public final class AnalysisHandler implements RequestHandler {
// *** retrieve method argument values ***
final Method analysisMethod = amh.getAnalysisMethod();
final Method method = amh.getAnalysisMethod ();
// read the length of argument data in the request
final short argsLength = is.readShort ();
if (argsLength < 0) {
throw new DiSLREServerException (String.format (
"invalid value of marshalled argument data length for analysis method %d (%s.%s): %d",
methodId, method.getDeclaringClass ().getName (),
method.getName (), argsLength
));
}
// read argument values data according to argument types
int readLength = 0;
final List <Object> args = new LinkedList <Object> ();
for (Class <?> argClass : analysisMethod.getParameterTypes ()) {
Object argValue = readType (is, argClass, analysisMethod);
args.add (argValue);
for (Class <?> argClass : method.getParameterTypes ()) {
readLength += unmarshalAndCollectArgument (
is, argClass, method, args
);
}
if (readLength != argsLength) {
throw new DiSLREServerException (String.format (
"received %d, but unmarshalled %d bytes of argument data for analysis method %d (%s.%s)",
argsLength, readLength, methodId, method.getDeclaringClass ().getName (),
method.getName ()
));
}
// *** create analysis invocation ***
......@@ -75,11 +112,11 @@ public final class AnalysisHandler implements RequestHandler {
System.out.printf (
"DiSL-RE: dispatching analysis method (%d) to %s.%s()\n",
methodId, amh.getAnalysisInstance().getClass().getSimpleName (),
analysisMethod.getName()
method.getName()
);
}
return new AnalysisInvocation (
analysisMethod, amh.getAnalysisInstance (), args
method, amh.getAnalysisInstance (), args
);
} catch (final IOException ioe) {
......@@ -90,103 +127,114 @@ public final class AnalysisHandler implements RequestHandler {
}
private Object readType(DataInputStream is, Class<?> argClass,
Method analysisMethod) throws IOException, DiSLREServerException {
private int unmarshalAndCollectArgument (
final DataInputStream is, final Class <?> argClass,
final Method analysisMethod, List <Object> args
) throws IOException, DiSLREServerException {
if(argClass.equals(boolean.class)) {
return is.readBoolean();
if (argClass.equals (boolean.class)) {
args.add (is.readBoolean ());
return Byte.SIZE / Byte.SIZE;
}
if(argClass.equals(char.class)) {
return is.readChar();
if (argClass.equals (char.class)) {
args.add (is.readChar ());
return Character.SIZE / Byte.SIZE;
}
if(argClass.equals(byte.class)) {
return is.readByte();
if (argClass.equals (byte.class)) {
args.add (is.readByte ());
return Byte.SIZE / Byte.SIZE;
}
if(argClass.equals(short.class)) {
return is.readShort();
if (argClass.equals (short.class)) {
args.add (is.readShort ());
return Short.SIZE / Byte.SIZE;
}
if(argClass.equals(int.class)) {
return is.readInt();
if (argClass.equals (int.class)) {
args.add (is.readInt ());
return Integer.SIZE / Byte.SIZE;
}
if(argClass.equals(long.class)) {
return is.readLong();
if (argClass.equals (long.class)) {
args.add (is.readLong ());
return Long.SIZE / Byte.SIZE;
}
if(argClass.equals(float.class)) {
return is.readFloat();
if (argClass.equals (float.class)) {
args.add (is.readFloat ());
return Float.SIZE / Byte.SIZE;
}
if(argClass.equals(double.class)) {
return is.readDouble();
if (argClass.equals (double.class)) {
args.add (is.readDouble ());
return Double.SIZE / Byte.SIZE;
}
if(argClass.equals(String.class)) {
long netRefNum = is.readLong();
// null handling
if(netRefNum == 0) {
return null;
if (argClass.equals (String.class)) {
long netRefNum = is.readLong ();
if (netRefNum != 0) {
// read string net reference and resolve it from cache
NetReference stringNR = new NetReference (netRefNum);
args.add (StringCache.resolve (stringNR.getObjectId ()));
} else {
// null handling
args.add (null);
}
// read string net reference
NetReference stringNR = new NetReference(netRefNum);
// resolve string from cache
return StringCache.resolve(stringNR.getObjectId());
return Long.SIZE / Byte.SIZE;
}
// read id only
// covers Object and NetReference classes
if(argClass.isAssignableFrom(NetReference.class)) {
long netRefNum = is.readLong();
// null handling
if(netRefNum == 0) {
return null;
if (argClass.isAssignableFrom (NetReference.class)) {
long netRefNum = is.readLong ();
if (netRefNum != 0) {
// TODO: Lookup the reference
args.add (new NetReference (netRefNum));
} else {
// null handling
args.add (null);
}
return new NetReference(netRefNum);
return Long.SIZE / Byte.SIZE;
}
// return ClassInfo object
if(argClass.equals(ClassInfo.class)) {
int classNetRefNum = is.readInt();
// null handling
if(classNetRefNum == 0) {
return null;
if (argClass.equals (ClassInfo.class)) {
int classNetRefNum = is.readInt ();
if (classNetRefNum != 0) {
args.add (ClassInfoResolver.getClass (classNetRefNum));
} else {
// null handling
args.add (null);
}
return ClassInfoResolver.getClass(classNetRefNum);
return Integer.SIZE / Byte.SIZE;
}
// return "invalid" class object
if(argClass.equals(Class.class)) {
return InvalidClass.class;
if (argClass.equals (Class.class)) {
args.add (InvalidClass.class);
return 0;
}
throw new DiSLREServerException(
"Unsupported data type "
+ argClass.toString()
+ " in analysis method "
+ analysisMethod.getDeclaringClass().toString()
+ "."
+ analysisMethod.toString());
throw new DiSLREServerException (String.format (
"Unsupported data type %s in analysis method %s.%s",
argClass.getName (), analysisMethod.getDeclaringClass ().getName (),
analysisMethod.getName ()
));
}
public void awaitProcessing() {
dispatcher.awaitProcessing();
public void awaitProcessing () {
dispatcher.awaitProcessing ();
}
public void exit() {
dispatcher.exit();
public void exit () {
dispatcher.exit ();
}
}
package ch.usi.dag.dislreserver.msg.analyze;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -11,26 +13,28 @@ import ch.usi.dag.dislreserver.exception.DiSLREServerFatalException;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import ch.usi.dag.dislreserver.stringcache.StringCache;
public class AnalysisResolver {
public final class AnalysisResolver {
private static final String METHOD_DELIM = ".";
private static final Map <Short, AnalysisMethodHolder>
methodMap = new HashMap <Short, AnalysisMethodHolder> ();
private static final Map <String, RemoteAnalysis>
analysisMap = new HashMap <String, RemoteAnalysis> ();
private static final Map<Short, AnalysisMethodHolder> methodMap =
new HashMap<Short, AnalysisMethodHolder>();
private static final Map<String, RemoteAnalysis> analysisMap =
new HashMap<String, RemoteAnalysis>();
// for fast set access - contains all values from analysisMap
private static final Set<RemoteAnalysis> analysisSet =
new HashSet<RemoteAnalysis>();
public static class AnalysisMethodHolder {
RemoteAnalysis analysisInstance;
Method analysisMethod;
public AnalysisMethodHolder(RemoteAnalysis analysisInstance,
Method analysisMethod) {
super();
private static final Set <RemoteAnalysis>
analysisSet = new HashSet <RemoteAnalysis> ();
//
public static final class AnalysisMethodHolder {
private final RemoteAnalysis analysisInstance;
private final Method analysisMethod;
public AnalysisMethodHolder(
final RemoteAnalysis analysisInstance, final Method analysisMethod
) {
this.analysisInstance = analysisInstance;
this.analysisMethod = analysisMethod;
}
......@@ -38,64 +42,45 @@ public class AnalysisResolver {
public RemoteAnalysis getAnalysisInstance() {
return analysisInstance;
}
public Method getAnalysisMethod() {
return analysisMethod;
}
}
private static AnalysisMethodHolder resolveMethod(long methodStringId)
throws DiSLREServerException {
//
private static AnalysisMethodHolder resolveMethod (
final long methodStringId
) throws DiSLREServerException {
try {
final String METHOD_DELIM = ".";
String methodStr = StringCache.resolve(methodStringId);
int classNameEnd = methodStr.lastIndexOf(METHOD_DELIM);
String methodStr = StringCache.resolve (methodStringId);
int classNameEnd = methodStr.lastIndexOf (METHOD_DELIM);
// without METHOD_DELIM
String className = methodStr.substring(0, classNameEnd);
String methodName = methodStr.substring(classNameEnd + 1);
String className = methodStr.substring (0, classNameEnd);
String methodName = methodStr.substring (classNameEnd + 1);
// resolve analysis instance
RemoteAnalysis raInst = analysisMap.get(className);
if(raInst == null) {
RemoteAnalysis raInst = analysisMap.get (className);
if (raInst == null) {
// resolve class
Class<?> raClass = Class.forName(className);
Class <?> raClass = Class.forName (className);
// create instance
raInst = (RemoteAnalysis) raClass.newInstance();
analysisMap.put(className, raInst);
analysisSet.add(raInst);
raInst = (RemoteAnalysis) raClass.newInstance ();
analysisMap.put (className, raInst);
analysisSet.add (raInst);
}
// resolve analysis method
Class<?> raClass = raInst.getClass();
Method raMethod = null;
for(Method m : raClass.getMethods()) {
if(m.getName().equals(methodName)) {
// TODO re - check for other methods with same name
// TODO re - write to docs - RemoteAnalysis.class
raMethod = m;
}
}
final Method raMethod = __getAnalysisMethod (raInst, methodName);
// TODO re - check that method has after each Class<?> arg, int arg
return new AnalysisMethodHolder(raInst, raMethod);
}
catch (ClassNotFoundException e) {
throw new DiSLREServerException(e);
} catch (InstantiationException e) {
......@@ -105,27 +90,58 @@ public class AnalysisResolver {
}
}
public static AnalysisMethodHolder getMethod(short methodId)
throws DiSLREServerException {
AnalysisMethodHolder result = methodMap.get(methodId);
if(result == null) {
throw new DiSLREServerFatalException("Unknown method id: " + methodId);
private static Method __getAnalysisMethod (
final RemoteAnalysis analysis, final String methodName
) throws DiSLREServerException {
final Class <?> analysisClass = analysis.getClass ();
final List <Method> methods = new ArrayList <Method> ();
for (final Method analysisMethod : analysisClass.getMethods ()) {
if (analysisMethod.getName ().equals (methodName)) {
methods.add (analysisMethod);
}
}
//
// Throw an exception if there are multiple methods
//
final int methodCount = methods.size ();
if (methodCount == 1) {
return methods.get (0);
} else if (methodCount > 1) {
throw new DiSLREServerException (String.format (
"Multiple methods matching \"%s\" found in %s",
methodName, analysisClass.getName ()
));
} else {
throw new DiSLREServerException (String.format (
"No method matching \"%s\" found in %s",
methodName, analysisClass.getName ()
));
}
}
static AnalysisMethodHolder getMethod (final short methodId)
throws DiSLREServerException {
AnalysisMethodHolder result = methodMap.get (methodId);
if (result == null) {
throw new DiSLREServerFatalException ("Unknown method id: "+ methodId);
}
return result;
}
public static void registerMethodId(short methodId, long methodStringId)
throws DiSLREServerException {
public static void registerMethodId (
final short methodId, final long methodStringId
) throws DiSLREServerException {
methodMap.put(methodId, resolveMethod(methodStringId));
}
public static Set<RemoteAnalysis> getAllAnalyses() {
public static Set <RemoteAnalysis> getAllAnalyses () {
return analysisSet;
}
}
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