From 1c21d758af81d880ad6e045d18f8bc62ad8be89e Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sun, 24 Jan 2010 09:27:44 +0000 Subject: Minor improvements to java component support, use one classloader per component, use Iterables instead of arrays to represent lists, added more tests and a working java version of the store integration test. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@902539 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/modules/java/eval.hpp | 137 +++++++++++++++++++++++++++++------- 1 file changed, 110 insertions(+), 27 deletions(-) (limited to 'sca-cpp/trunk/modules/java/eval.hpp') diff --git a/sca-cpp/trunk/modules/java/eval.hpp b/sca-cpp/trunk/modules/java/eval.hpp index 7641c5de79..9dbb50abb5 100644 --- a/sca-cpp/trunk/modules/java/eval.hpp +++ b/sca-cpp/trunk/modules/java/eval.hpp @@ -52,31 +52,45 @@ public: JavaVMInitArgs args; args.version = JNI_VERSION_1_6; args.ignoreUnrecognized = JNI_FALSE; - JavaVMOption options[1]; - options[0].optionString = const_cast("-Djava.class.path=."); + JavaVMOption options[3]; args.options = options; - args.nOptions = 1; + args.nOptions = 0; + + // Configure classpath + const char* envcp = getenv("CLASSPATH"); + const string cp = string("-Djava.class.path=") + (envcp == NULL? "." : envcp); + options[args.nOptions++].optionString = const_cast(c_str(cp)); + +#ifdef WANT_MAINTAINER_MODE + // Enable assertions + options[args.nOptions++].optionString = const_cast("-ea"); +#endif + + // Configure Java debugging + const char* jpdaopts = getenv("JPDA_OPTS"); + if (jpdaopts != NULL) { + options[args.nOptions++].optionString = const_cast(jpdaopts); + } else { + const char* jpdaaddr = getenv("JPDA_ADDRESS"); + if (jpdaaddr != NULL) { + const string jpda = string("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=") + jpdaaddr; + options[args.nOptions++].optionString = const_cast(c_str(jpda)); + } + } + + // Create the JVM JNI_CreateJavaVM(&jvm, (void**)&env, &args); - // Register our native invocation handler function - invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); - JNINativeMethod nm; - nm.name = const_cast("invoke"); - nm.signature = const_cast("(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); - nm.fnPtr = (void*)nativeInvoke; - env->RegisterNatives(invokerClass, &nm, 1); - } else { - // Just hook to existing JVM + // Just point to existing JVM jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); } // Capture JVM standard IO setupIO(); - // Lookup the classes and methods we need + // Lookup System classes and methods classClass = env->FindClass("java/lang/Class"); methodClass = env->FindClass("java/lang/reflect/Method"); objectClass = env->FindClass("java/lang/Object"); @@ -84,6 +98,8 @@ public: booleanClass = env->FindClass("java/lang/Boolean"); stringClass = env->FindClass("java/lang/String"); objectArrayClass = env->FindClass("[Ljava/lang/Object;"); + iterableClass = env->FindClass("Ljava/lang/Iterable;"); + classForName = env->GetStaticMethodID(classClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); doubleValueOf = env->GetStaticMethodID(doubleClass, "valueOf", "(D)Ljava/lang/Double;"); doubleValue = env->GetMethodID(doubleClass, "doubleValue", "()D"); booleanValueOf = env->GetStaticMethodID(booleanClass, "valueOf", "(Z)Ljava/lang/Boolean;"); @@ -91,8 +107,27 @@ public: declaredMethods = env->GetMethodID(classClass, "getDeclaredMethods", "()[Ljava/lang/reflect/Method;"); methodName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;"); parameterTypes = env->GetMethodID(methodClass, "getParameterTypes", "()[Ljava/lang/Class;"); + + // Lookup Tuscany classes and methods + loaderClass = env->FindClass("org/apache/tuscany/ClassLoader"); + loaderValueOf = env->GetStaticMethodID(loaderClass, "valueOf", "(Ljava/lang/String;)Ljava/lang/ClassLoader;"); + loaderForName = env->GetStaticMethodID(loaderClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"); + invokerClass = env->FindClass("org/apache/tuscany/InvocationHandler"); invokerValueOf = env->GetStaticMethodID(invokerClass, "valueOf", "(Ljava/lang/Class;J)Ljava/lang/Object;"); invokerLambda = env->GetFieldID(invokerClass, "lambda", "J"); + iterableUtilClass = env->FindClass("org/apache/tuscany/IterableUtil"); + iterableValueOf = env->GetStaticMethodID(iterableUtilClass, "list", "([Ljava/lang/Object;)Ljava/lang/Iterable;"); + iterableIsNil = env->GetStaticMethodID(iterableUtilClass, "isNil", "(Ljava/lang/Object;)Z"); + iterableCar = env->GetStaticMethodID(iterableUtilClass, "car", "(Ljava/lang/Object;)Ljava/lang/Object;"); + iterableCdr = env->GetStaticMethodID(iterableUtilClass, "cdr", "(Ljava/lang/Object;)Ljava/lang/Iterable;"); + + // Register our native invocation handler function + JNINativeMethod nm; + nm.name = const_cast("invoke"); + nm.signature = const_cast("(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); + nm.fnPtr = (void*)nativeInvoke; + env->RegisterNatives(invokerClass, &nm, 1); + } JavaVM* jvm; @@ -105,6 +140,7 @@ public: jclass booleanClass; jclass stringClass; jclass objectArrayClass; + jclass iterableClass; jmethodID doubleValueOf; jmethodID doubleValue; jmethodID booleanValueOf; @@ -112,10 +148,18 @@ public: jmethodID declaredMethods; jmethodID methodName; jmethodID parameterTypes; - + jmethodID classForName; + jclass loaderClass; + jmethodID loaderValueOf; + jmethodID loaderForName; jclass invokerClass; jmethodID invokerValueOf; jfieldID invokerLambda; + jclass iterableUtilClass; + jmethodID iterableValueOf; + jmethodID iterableCar; + jmethodID iterableCdr; + jmethodID iterableIsNil; } javaRuntime; @@ -137,6 +181,7 @@ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const va const value jobjectToValue(const JavaRuntime& jr, const jobject o); const jobjectArray valuesToJarray(const JavaRuntime& jr, const list& v); const list jarrayToValues(const JavaRuntime& jr, const jobjectArray o); +const list jiterableToValues(const JavaRuntime& jr, const jobject o); /** * Convert a Java class name to a JNI class name. @@ -204,9 +249,11 @@ jobject JNICALL nativeInvoke(JNIEnv* env, jobject self, unused jobject proxy, jo // Build the expression to evaluate const list expr = cons(func, jarrayToValues(jl.jr, args)); + debug(expr, "java::nativeInvoke::expr"); // Invoke the lambda function value result = jl(expr); + debug(result, "java::nativeInvoke::result"); // Convert result to a jobject return valueToJobject(jl.jr, value(), result); @@ -237,13 +284,20 @@ const jobjectArray valuesToJarray(const JavaRuntime& jr, const list& v) { return valuesToJarrayHelper(jr, a, v, 0); } +/** + * Convert a Java jobjectArray to a Java iterable. + */ +const jobject jarrayToJiterable(const JavaRuntime& jr, jobjectArray a) { + return jr.env->CallStaticObjectMethod(jr.iterableClass, jr.iterableValueOf, a); +} + /** * Convert a value to a Java jobject. */ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const value& v) { switch (type(v)) { case value::List: - return valuesToJarray(jr, v); + return jarrayToJiterable(jr, valuesToJarray(jr, v)); case value::Lambda: return mkJavaLambda(jr, jtype, v); case value::Symbol: @@ -253,7 +307,7 @@ const jobject valueToJobject(const JavaRuntime& jr, const value& jtype, const va case value::Number: return jr.env->CallStaticObjectMethod(jr.doubleClass, jr.doubleValueOf, (double)v); case value::Bool: - return jr.env->CallStaticObjectMethod(jr.booleanClass, jr.booleanValueOf, (double)v); + return jr.env->CallStaticObjectMethod(jr.booleanClass, jr.booleanValueOf, (bool)v); default: return NULL; } @@ -291,6 +345,23 @@ const list jarrayToValues(const JavaRuntime& jr, jobjectArray o) { return jarrayToValuesHelper(jr, o, 0, jr.env->GetArrayLength(o)); } +/** + * Convert a Java Iterable to a list of values. + */ +const list jiterableToValuesHelper(const JavaRuntime& jr, jobject o) { + if ((bool)jr.env->CallStaticBooleanMethod(jr.iterableUtilClass, jr.iterableIsNil, o)) + return list(); + jobject car = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCar, o); + jobject cdr = jr.env->CallStaticObjectMethod(jr.iterableUtilClass, jr.iterableCdr, o); + return cons(jobjectToValue(jr, car), jiterableToValuesHelper(jr, cdr)); +} + +const list jiterableToValues(const JavaRuntime& jr, jobject o) { + if (o == NULL) + return list(); + return jiterableToValuesHelper(jr, o); +} + /** * Lambda function used to represent a Java callable object. */ @@ -330,8 +401,8 @@ const value jobjectToValue(const JavaRuntime& jr, const jobject o) { return value((bool)jr.env->CallBooleanMethod(o, jr.booleanValue)); if (jr.env->IsSameObject(clazz, jr.doubleClass)) return value((double)jr.env->CallDoubleMethod(o, jr.doubleValue)); - if ((jr.env->IsSameObject(clazz, jr.objectArrayClass))) - return jarrayToValues(jr, (jobjectArray)o); + if ((jr.env->IsAssignableFrom(clazz, jr.iterableClass))) + return jiterableToValues(jr, o); return lambda&)>(javaCallable(jr, o)); } @@ -378,12 +449,12 @@ const list methodsToValues(const JavaRuntime& jr, const jclass clazz) { */ class JavaClass { public: - JavaClass() : clazz(NULL), obj(NULL) { + JavaClass() : loader(NULL), clazz(NULL), obj(NULL) { } - - JavaClass(const jclass clazz, const jobject obj, const list m) : clazz(clazz), obj(obj), m(m) { + JavaClass(const jobject loader, const jclass clazz, const jobject obj, const list m) : loader(loader), clazz(clazz), obj(obj), m(m) { } + const jobject loader; const jclass clazz; const jobject obj; const list m; @@ -392,24 +463,34 @@ public: /** * Read a class. */ -const failable readClass(const JavaRuntime& jr, const string& name) { - const string jname = jniClassName(name); - const jclass clazz = jr.env->FindClass(c_str(jname)); +const failable readClass(const JavaRuntime& jr, const string& path, const string& name) { + + // Create a class loader from the given path + const jobject jpath = jr.env->NewStringUTF(c_str(path)); + jobject loader = jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderValueOf, jpath); + + // Load the class + const jobject jname = jr.env->NewStringUTF(c_str(name)); + const jclass clazz = (jclass)jr.env->CallStaticObjectMethod(jr.loaderClass, jr.loaderForName, jname, JNI_TRUE, loader); if (clazz == NULL) return mkfailure(string("Couldn't load class: ") + name + " : " + lastException(jr)); + + // Create an instance const jmethodID constr = jr.env->GetMethodID(clazz, "", "()V"); if (constr == NULL) return mkfailure(string("Couldn't find constructor: ") + name + " : " + lastException(jr)); const jobject obj = jr.env->NewObject(clazz, constr); if (obj == NULL) return mkfailure(string("Couldn't construct object: ") + name + " : " + lastException(jr)); - return JavaClass(clazz, obj, methodsToValues(jr, clazz)); + + return JavaClass(loader, clazz, obj, methodsToValues(jr, clazz)); } /** * Evaluate an expression against a Java class. */ const failable evalClass(const JavaRuntime& jr, const value& expr, const JavaClass jc) { + debug(expr, "java::evalClass::expr"); // Lookup the Java function named as the expression operand const list func = assoc(car(expr), jc.m); @@ -426,7 +507,9 @@ const failable evalClass(const JavaRuntime& jr, const value& expr, const return mkfailure(string("Function call failed: ") + car(expr) + " : " + lastException(jr)); // Convert Java result to a value - return jobjectToValue(jr, result); + const value v = jobjectToValue(jr, result); + debug(v, "java::evalClass::result"); + return v; } } -- cgit v1.2.3