#include "java.h" #include #ifdef WIN32 #else #include #endif #include "javaObject.h" #include "javaScope.h" #include "methodCallBaton.h" #include "node_NodeDynamicProxyClass.h" #include #include #include #define DYNAMIC_PROXY_JS_ERROR -4 long v8ThreadId; /*static*/ v8::Persistent<:functiontemplate> Java::s_ct; /*static*/ std::string Java::s_nativeBindingLocation; void my_sleep(int dur) { #ifdef WIN32 Sleep(dur); #else usleep(dur); #endif } long my_getThreadId() { #ifdef WIN32 return (long)GetCurrentThreadId(); #else return (long)pthread_self(); #endif } /*static*/ void Java::Init(v8::Handle<:object> target) { NanScope(); v8ThreadId = my_getThreadId(); v8::Local<:functiontemplate> t = NanNew<:functiontemplate>(New); NanAssignPersistent(s_ct, t); t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(NanNew<:string>("Java")); NODE_SET_PROTOTYPE_METHOD(t, "getClassLoader", getClassLoader); NODE_SET_PROTOTYPE_METHOD(t, "newInstance", newInstance); NODE_SET_PROTOTYPE_METHOD(t, "newInstanceSync", newInstanceSync); NODE_SET_PROTOTYPE_METHOD(t, "newProxy", newProxy); NODE_SET_PROTOTYPE_METHOD(t, "callStaticMethod", callStaticMethod); NODE_SET_PROTOTYPE_METHOD(t, "callStaticMethodSync", callStaticMethodSync); NODE_SET_PROTOTYPE_METHOD(t, "callMethod", callMethod); NODE_SET_PROTOTYPE_METHOD(t, "callMethodSync", callMethodSync); NODE_SET_PROTOTYPE_METHOD(t, "findClassSync", findClassSync); NODE_SET_PROTOTYPE_METHOD(t, "newArray", newArray); NODE_SET_PROTOTYPE_METHOD(t, "newByte", newByte); NODE_SET_PROTOTYPE_METHOD(t, "newShort", newShort); NODE_SET_PROTOTYPE_METHOD(t, "newLong", newLong); NODE_SET_PROTOTYPE_METHOD(t, "newChar", newChar); NODE_SET_PROTOTYPE_METHOD(t, "newFloat", newFloat); NODE_SET_PROTOTYPE_METHOD(t, "newDouble", newDouble); NODE_SET_PROTOTYPE_METHOD(t, "getStaticFieldValue", getStaticFieldValue); NODE_SET_PROTOTYPE_METHOD(t, "setStaticFieldValue", setStaticFieldValue); NODE_SET_PROTOTYPE_METHOD(t, "instanceOf", instanceOf); target->Set(NanNew<:string>("Java"), t->GetFunction()); JavaProxyObject::init(); } NAN_METHOD(Java::New) { NanScope(); Java *self = new Java(); self->Wrap(args.This()); NanObjectWrapHandle(self)->Set(NanNew<:string>("classpath"), NanNew<:array>()); NanObjectWrapHandle(self)->Set(NanNew<:string>("options"), NanNew<:array>()); NanObjectWrapHandle(self)->Set(NanNew<:string>("nativeBindingLocation"), NanNew<:string>("Not Set")); NanObjectWrapHandle(self)->Set(NanNew<:string>("asyncOptions"), NanNull()); NanReturnValue(args.This()); } Java::Java() { this->m_jvm = NULL; this->m_env = NULL; } Java::~Java() { this->destroyJVM(&this->m_jvm, &this->m_env); } v8::Local<:value> Java::ensureJvm() { if(!m_jvm) { return createJVM(&this->m_jvm, &this->m_env); } return NanNull(); } v8::Local<:value> Java::createJVM(JavaVM** jvm, JNIEnv** env) { JavaVM* jvmTemp; JavaVMInitArgs args; v8::Local<:value> asyncOptions = NanObjectWrapHandle(this)->Get(NanNew<:string>("asyncOptions")); if (asyncOptions->IsObject()) { v8::Local<:object> asyncOptionsObj = asyncOptions.As<:object>(); v8::Local<:value> promisify = asyncOptionsObj->Get(NanNew<:string>("promisify")); if (!promisify->IsFunction()) { return NanTypeError("asyncOptions.promisify must be a function"); } v8::Local<:value> suffix = asyncOptionsObj->Get(NanNew<:string>("promiseSuffix")); if (!suffix->IsString()) { return NanTypeError("asyncOptions.promiseSuffix must be a string"); } NanAssignPersistent(m_asyncOptions, asyncOptionsObj); } // setup classpath std::ostringstream classPath; classPath classPathValue = NanObjectWrapHandle(this)->Get(NanNew<:string>("classpath")); if(!classPathValue->IsArray()) { return NanTypeError("Classpath must be an array"); } v8::Handle<:array> classPathArrayTemp = v8::Handle<:array>::Cast(classPathValue); NanAssignPersistent(m_classPathArray, classPathArrayTemp); for(uint32_t i=0; iLength(); i++) { if(i != 0) { #ifdef WIN32 classPath arrayItemValue = classPathArrayTemp->Get(i); if(!arrayItemValue->IsString()) { return NanTypeError("Classpath must only contain strings"); } v8::Local<:string> arrayItem = arrayItemValue->ToString(); v8::String::Utf8Value arrayItemStr(arrayItem); classPath v8NativeBindingLocation = NanObjectWrapHandle(this)->Get(NanNew<:string>("nativeBindingLocation")); v8::String::Utf8Value nativeBindingLocationStr(v8NativeBindingLocation); s_nativeBindingLocation = *nativeBindingLocationStr; // get other options v8::Local<:value> optionsValue = NanObjectWrapHandle(this)->Get(NanNew<:string>("options")); if(!optionsValue->IsArray()) { return NanTypeError("options must be an array"); } v8::Handle<:array> optionsArrayTemp = v8::Handle<:array>::Cast(optionsValue); NanAssignPersistent(m_optionsArray, optionsArrayTemp); // create vm options int vmOptionsCount = optionsArrayTemp->Length() + 1; JavaVMOption* vmOptions = new JavaVMOption[vmOptionsCount]; //printf("classPath: %s\n", classPath.str().c_str()); vmOptions[0].optionString = strdup(classPath.str().c_str()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> arrayItemValue = optionsArrayTemp->Get(i); if(!arrayItemValue->IsString()) { delete[] vmOptions; return NanTypeError("options must only contain strings"); } v8::Local<:string> arrayItem = arrayItemValue->ToString(); v8::String::Utf8Value arrayItemStr(arrayItem); vmOptions[i+1].optionString = strdup(*arrayItemStr); } JNI_GetDefaultJavaVMInitArgs(&args); args.version = JNI_BEST_VERSION; args.ignoreUnrecognized = false; args.options = vmOptions; args.nOptions = vmOptionsCount; JNI_CreateJavaVM(&jvmTemp, (void **)env, &args); *jvm = jvmTemp; m_classLoader = getSystemClassLoader(*env); v8::Local<:value> onJvmCreated = NanObjectWrapHandle(this)->Get(NanNew<:string>("onJvmCreated")); // TODO: this handles sets put doesn't prevent modifing the underlying data. So java.classpath.push will still work which is invalid. NanObjectWrapHandle(this)->SetAccessor(NanNew<:string>("classpath"), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); NanObjectWrapHandle(this)->SetAccessor(NanNew<:string>("options"), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); NanObjectWrapHandle(this)->SetAccessor(NanNew<:string>("nativeBindingLocation"), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); NanObjectWrapHandle(this)->SetAccessor(NanNew<:string>("asyncOptions"), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); NanObjectWrapHandle(this)->SetAccessor(NanNew<:string>("onJvmCreated"), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter); if (onJvmCreated->IsFunction()) { v8::Local<:function> onJvmCreatedFunc = onJvmCreated.As<:function>(); v8::Local<:object> context = NanNew<:object>(); onJvmCreatedFunc->Call(context, 0, NULL); } return NanNull(); } NAN_GETTER(Java::AccessorProhibitsOverwritingGetter) { Java* self = node::ObjectWrap::Unwrap(args.This()); NanScope(); v8::String::Utf8Value nameStr(property); if(!strcmp("classpath", *nameStr)) { NanReturnValue(self->m_classPathArray); } else if(!strcmp("options", *nameStr)) { NanReturnValue(self->m_optionsArray); } else if(!strcmp("nativeBindingLocation", *nameStr)) { NanReturnValue(NanNew<:string>(Java::s_nativeBindingLocation.c_str())); } else if(!strcmp("asyncOptions", *nameStr)) { NanReturnValue(self->m_asyncOptions); } else if(!strcmp("onJvmCreated", *nameStr)) { // There is no good reason to get onJvmCreated, so just fall through to error below. } std::ostringstream errStr; errStr (errStr.str().c_str()))); } NAN_SETTER(Java::AccessorProhibitsOverwritingSetter) { v8::String::Utf8Value nameStr(property); std::ostringstream errStr; errStr DestroyJavaVM(); *jvm = NULL; *env = NULL; } NAN_METHOD(Java::getClassLoader) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Local<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); jclass classClazz = env->FindClass("java/lang/ClassLoader"); jmethodID class_getClassLoader = env->GetStaticMethodID(classClazz, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); jobject classLoader = env->CallStaticObjectMethod(classClazz, class_getClassLoader); checkJavaException(env); jobject result = env->NewGlobalRef(classLoader); NanReturnValue(javaToV8(self, env, result)); } NAN_METHOD(Java::newInstance) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_CLASSNAME(); ARGS_BACK_CALLBACK(); // find class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { EXCEPTION_CALL_CALLBACK(self, "Could not find class " run(); END_CALLBACK_FUNCTION("\"Constructor for class '" (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_CLASSNAME(); // find class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr callback = NanNull(); NewInstanceBaton* baton = new NewInstanceBaton(self, clazz, method, methodArgs, callback); v8::Handle<:value> result = baton->runSync(); delete baton; if(result->IsNativeError()) { return NanThrowError(result); } NanReturnValue(result); } NAN_METHOD(Java::newProxy) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; ARGS_FRONT_STRING(interfaceName); ARGS_FRONT_OBJECT(functions); DynamicProxyData* dynamicProxyData = new DynamicProxyData(); dynamicProxyData->markerStart = DYNAMIC_PROXY_DATA_MARKER_START; dynamicProxyData->markerEnd = DYNAMIC_PROXY_DATA_MARKER_END; dynamicProxyData->java = self; dynamicProxyData->interfaceName = interfaceName; NanAssignPersistent(dynamicProxyData->functions, functions); // find NodeDynamicProxyClass std::string className = "node.NodeDynamicProxyClass"; jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr FindClass("java/lang/Object"); jobjectArray methodArgs = env->NewObjectArray(2, objectClazz, NULL); env->SetObjectArrayElement(methodArgs, 0, v8ToJava(env, NanNew<:string>(s_nativeBindingLocation.c_str()))); env->SetObjectArrayElement(methodArgs, 1, longToJavaLongObj(env, (long)dynamicProxyData)); jobject method = javaFindConstructor(env, clazz, methodArgs); if(method == NULL) { std::ostringstream errStr; errStr FindClass("java/lang/reflect/Constructor"); jmethodID constructor_newInstance = env->GetMethodID(constructorClazz, "newInstance", "([Ljava/lang/Object;)Ljava/lang/Object;"); //printf("invoke: %s\n", javaMethodCallToString(env, m_method, constructor_newInstance, m_args).c_str()); // run constructor jobject dynamicProxy = env->CallObjectMethod(method, constructor_newInstance, methodArgs); if(env->ExceptionCheck()) { std::ostringstream errStr; errStr FindClass("java/lang/Class"); jobjectArray classArray = env->NewObjectArray(1, classClazz, NULL); if(classArray == NULL) { std::ostringstream errStr; errStr SetObjectArrayElement(classArray, 0, dynamicInterface); jmethodID class_getClassLoader = env->GetMethodID(classClazz, "getClassLoader", "()Ljava/lang/ClassLoader;"); jobject classLoader = env->CallObjectMethod(dynamicInterface, class_getClassLoader); assert(!env->ExceptionCheck()); if(classLoader == NULL) { jclass objectClazz = env->FindClass("java/lang/Object"); jmethodID object_getClass = env->GetMethodID(objectClazz, "getClass", "()Ljava/lang/Class;"); jobject jobjClass = env->CallObjectMethod(dynamicProxy, object_getClass); checkJavaException(env); classLoader = env->CallObjectMethod(jobjClass, class_getClassLoader); checkJavaException(env); } if(classLoader == NULL) { std::ostringstream errStr; errStr FindClass("java/lang/reflect/Proxy"); jmethodID proxy_newProxyInstance = env->GetStaticMethodID(proxyClass, "newProxyInstance", "(Ljava/lang/ClassLoader;[Ljava/lang/Class;Ljava/lang/reflect/InvocationHandler;)Ljava/lang/Object;"); jobject proxyInstance = env->CallStaticObjectMethod(proxyClass, proxy_newProxyInstance, classLoader, classArray, dynamicProxy); if(env->ExceptionCheck()) { std::ostringstream errStr; errStr result = javaToV8(self, env, proxyInstance, dynamicProxyData); NanAssignPersistent(dynamicProxyData->jsObject, result); NanReturnValue(result); } NAN_METHOD(Java::callStaticMethod) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_CLASSNAME(); ARGS_FRONT_STRING(methodName); ARGS_BACK_CALLBACK(); // find class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { EXCEPTION_CALL_CALLBACK(self, "Could not create class " run(); END_CALLBACK_FUNCTION("\"Static method '" (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_CLASSNAME(); ARGS_FRONT_STRING(methodName); // find class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr callback = NanNull(); StaticMethodCallBaton* baton = new StaticMethodCallBaton(self, clazz, method, methodArgs, callback); v8::Handle<:value> result = baton->runSync(); delete baton; if(result->IsNativeError()) { return NanThrowError(result); } NanReturnValue(result); } NAN_METHOD(Java::callMethodSync) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_OBJECT(instanceObj); ARGS_FRONT_STRING(methodName); JavaObject* javaObj = node::ObjectWrap::Unwrap(instanceObj); // find method jclass clazz = javaObj->getClass(); jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, clazz, methodName, methodArgs); if(method == NULL) { std::string msg = methodNotFoundToString(env, clazz, methodName, false, args, argsStart, argsEnd); return NanThrowError(javaExceptionToV8(self, env, msg)); } // run v8::Handle<:value> callback = NanNull(); InstanceMethodCallBaton* baton = new InstanceMethodCallBaton(self, javaObj, method, methodArgs, callback); v8::Handle<:value> result = baton->runSync(); delete baton; if(result->IsNativeError()) { return NanThrowError(result); } NanReturnValue(result); } NAN_METHOD(Java::callMethod) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_FRONT_OBJECT(instanceObj); ARGS_FRONT_STRING(methodName); ARGS_BACK_CALLBACK(); JavaObject* javaObj = node::ObjectWrap::Unwrap(instanceObj); // find method jclass clazz = javaObj->getClass(); jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, clazz, methodName, methodArgs); if(method == NULL) { std::string msg = methodNotFoundToString(env, clazz, methodName, false, args, argsStart, argsEnd); EXCEPTION_CALL_CALLBACK(self, msg); NanReturnUndefined(); } // run InstanceMethodCallBaton* baton = new InstanceMethodCallBaton(self, javaObj, method, methodArgs, callback); baton->run(); END_CALLBACK_FUNCTION("\"method '" (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; // arguments ARGS_FRONT_CLASSNAME(); // find class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr result = javaToV8(self, env, clazz); NanReturnValue(result); } NAN_METHOD(Java::newArray) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; // arguments ARGS_FRONT_CLASSNAME(); // argument - array if(args.Length() IsArray()) { std::ostringstream errStr; errStr (errStr.str().c_str()))); } v8::Local<:array> arrayObj = v8::Local<:array>::Cast(args[argsStart]); // find class and method jarray results; if(strcmp(className.c_str(), "byte") == 0) { results = env->NewByteArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass byteClazz = env->FindClass("java/lang/Byte"); jmethodID byte_byteValue = env->GetMethodID(byteClazz, "byteValue", "()B"); jbyte byteValues[1]; byteValues[0] = env->CallByteMethod(val, byte_byteValue); assert(!env->ExceptionCheck()); env->SetByteArrayRegion((jbyteArray)results, i, 1, byteValues); } } else if(strcmp(className.c_str(), "char") == 0) { results = env->NewCharArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass stringClazz = env->FindClass("java/lang/String"); jmethodID string_charAt = env->GetMethodID(stringClazz, "charAt", "(I)C"); jchar itemValues[1]; itemValues[0] = env->CallCharMethod(val, string_charAt, 0); checkJavaException(env); env->SetCharArrayRegion((jcharArray)results, i, 1, itemValues); } } else if(strcmp(className.c_str(), "short") == 0) { results = env->NewShortArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass shortClazz = env->FindClass("java/lang/Short"); jmethodID short_shortValue = env->GetMethodID(shortClazz, "shortValue", "()S"); jshort shortValues[1]; shortValues[0] = env->CallShortMethod(val, short_shortValue); assert(!env->ExceptionCheck()); env->SetShortArrayRegion((jshortArray)results, i, 1, shortValues); } } else if(strcmp(className.c_str(), "double") == 0) { results = env->NewDoubleArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass doubleClazz = env->FindClass("java/lang/Double"); jmethodID double_doubleValue = env->GetMethodID(doubleClazz, "doubleValue", "()D"); jdouble doubleValues[1]; doubleValues[0] = env->CallDoubleMethod(val, double_doubleValue); assert(!env->ExceptionCheck()); env->SetDoubleArrayRegion((jdoubleArray)results, i, 1, doubleValues); } } else if(strcmp(className.c_str(), "int") == 0) { results = env->NewIntArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass integerClazz = env->FindClass("java/lang/Integer"); jmethodID integer_intValue = env->GetMethodID(integerClazz, "intValue", "()I"); jint intValues[1]; intValues[0] = env->CallIntMethod(val, integer_intValue); assert(!env->ExceptionCheck()); env->SetIntArrayRegion((jintArray)results, i, 1, intValues); } } else if(strcmp(className.c_str(), "boolean") == 0) { results = env->NewBooleanArray(arrayObj->Length()); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); jclass booleanClazz = env->FindClass("java/lang/Boolean"); jmethodID boolean_booleanValue = env->GetMethodID(booleanClazz, "booleanValue", "()Z"); jboolean booleanValues[1]; booleanValues[0] = env->CallBooleanMethod(val, boolean_booleanValue); checkJavaException(env); env->SetBooleanArrayRegion((jbooleanArray)results, i, 1, booleanValues); } } else { jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr NewObjectArray(arrayObj->Length(), clazz, NULL); for(uint32_t i=0; iLength(); i++) { v8::Local<:value> item = arrayObj->Get(i); jobject val = v8ToJava(env, item); env->SetObjectArrayElement((jobjectArray)results, i, val); if(env->ExceptionOccurred()) { std::ostringstream errStr; v8::String::Utf8Value valStr(item); errStr (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newByte only takes 1 argument"))); } // argument - value if(!args[0]->IsNumber()) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number"))); } v8::Local<:number> val = args[0]->ToNumber(); jclass clazz = env->FindClass("java/lang/Byte"); jmethodID constructor = env->GetMethodID(clazz, "", "(B)V"); jobject newObj = env->NewObject(clazz, constructor, (jbyte)val->Value()); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::newShort) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newShort only takes 1 argument"))); } // argument - value if(!args[0]->IsNumber()) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number"))); } v8::Local<:number> val = args[0]->ToNumber(); jclass clazz = env->FindClass("java/lang/Short"); jmethodID constructor = env->GetMethodID(clazz, "", "(S)V"); jobject newObj = env->NewObject(clazz, constructor, (jshort)val->Value()); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::newLong) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newLong only takes 1 argument"))); } // argument - value if(!args[0]->IsNumber()) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number"))); } v8::Local<:number> val = args[0]->ToNumber(); jclass clazz = env->FindClass("java/lang/Long"); jmethodID constructor = env->GetMethodID(clazz, "", "(J)V"); jobject newObj = env->NewObject(clazz, constructor, (jlong)val->Value()); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::newChar) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newChar only takes 1 argument"))); } // argument - value jchar charVal; if(args[0]->IsNumber()) { v8::Local<:number> val = args[0]->ToNumber(); charVal = (jchar)val->Value(); } else if(args[0]->IsString()) { v8::Local<:string> val = args[0]->ToString(); if(val->Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a string of 1 character."))); } std::string strVal = std::string(*v8::String::Utf8Value(val)); charVal = (jchar)strVal[0]; } else { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number or string"))); } jclass clazz = env->FindClass("java/lang/Character"); jmethodID constructor = env->GetMethodID(clazz, "", "(C)V"); jobject newObj = env->NewObject(clazz, constructor, charVal); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::newFloat) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newFloat only takes 1 argument"))); } else if(!args[0]->IsNumber()) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number"))); } v8::Local<:number> val = args[0]->ToNumber(); jclass clazz = env->FindClass("java/lang/Float"); jmethodID constructor = env->GetMethodID(clazz, "", "(F)V"); jobject newObj = env->NewObject(clazz, constructor, (jfloat)val->Value()); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::newDouble) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); if(args.Length() != 1) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("newDouble only takes 1 argument"))); } else if(!args[0]->IsNumber()) { return NanThrowError(v8::Exception::TypeError(NanNew<:string>("Argument 1 must be a number"))); } v8::Local<:number> val = args[0]->ToNumber(); jclass clazz = env->FindClass("java/lang/Double"); jmethodID constructor = env->GetMethodID(clazz, "", "(D)V"); jobject newObj = env->NewObject(clazz, constructor, (jdouble)val->Value()); NanReturnValue(JavaObject::New(self, newObj)); } NAN_METHOD(Java::getStaticFieldValue) { NanScope(); Java* self = node::ObjectWrap::Unwrap(args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; // arguments ARGS_FRONT_CLASSNAME(); ARGS_FRONT_STRING(fieldName); // find the class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr FindClass("java/lang/reflect/Field"); jmethodID field_get = env->GetMethodID(fieldClazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); // get field value jobject val = env->CallObjectMethod(field, field_get, NULL); if(env->ExceptionOccurred()) { std::ostringstream errStr; errStr (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; // arguments ARGS_FRONT_CLASSNAME(); ARGS_FRONT_STRING(fieldName); // argument - new value if(args.Length() (errStr.str().c_str()))); } jobject newValue = v8ToJava(env, args[argsStart]); argsStart++; // find the class jclass clazz = javaFindClass(env, className); if(clazz == NULL) { std::ostringstream errStr; errStr FindClass("java/lang/reflect/Field"); jmethodID field_set = env->GetMethodID(fieldClazz, "set", "(Ljava/lang/Object;Ljava/lang/Object;)V"); //printf("newValue: %s\n", javaObjectToString(env, newValue).c_str()); // set field value env->CallObjectMethod(field, field_set, NULL, newValue); if(env->ExceptionOccurred()) { std::ostringstream errStr; errStr (args.This()); v8::Handle<:value> ensureJvmResults = self->ensureJvm(); if(!ensureJvmResults->IsNull()) { NanReturnValue(ensureJvmResults); } JNIEnv* env = self->getJavaEnv(); JavaScope javaScope(env); int argsStart = 0; ARGS_FRONT_OBJECT(obj); ARGS_FRONT_STRING(className); jobject instance = v8ToJava(env, obj); if (!instance) { // not even a Java object NanReturnValue(NanNew<:boolean>(false)); } jclass clazz = javaFindClass(env, className); if(!clazz) { std::ostringstream errStr; errStr IsInstanceOf(instance, clazz); NanReturnValue(NanNew<:boolean>(res)); } void EIO_CallJs(uv_work_t* req) { } template std::string to_string(T value) { std::ostringstream os; os = 10 void EIO_AfterCallJs(uv_work_t* req, int status) { #else void EIO_AfterCallJs(uv_work_t* req) { #endif DynamicProxyData* dynamicProxyData = static_cast(req->data); if(!dynamicProxyDataVerify(dynamicProxyData)) { return; } dynamicProxyData->result = NULL; JNIEnv* env; int ret = dynamicProxyData->java->getJvm()->GetEnv((void**)&env, JNI_BEST_VERSION); if (ret != JNI_OK) { dynamicProxyData->throwableClass = "java/lang/IllegalStateException"; dynamicProxyData->throwableMessage = "Could not retrieve JNIEnv: jvm->GetEnv returned " + to_string(ret); dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } NanScope(); v8::Array* v8Args; v8::Function* fn; v8::Handle<:value>* argv; int argc; int i; v8::Local<:value> v8Result; jobject javaResult; v8::Local<:object> dynamicProxyDataFunctions = NanNew(dynamicProxyData->functions); v8::Local<:value> fnObj = dynamicProxyDataFunctions->Get(NanNew<:string>(dynamicProxyData->methodName.c_str())); if(fnObj->IsUndefined() || fnObj->IsNull()) { dynamicProxyData->throwableClass = "java/lang/NoSuchMethodError"; dynamicProxyData->throwableMessage = "Could not find js function " + dynamicProxyData->methodName; dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } if(!fnObj->IsFunction()) { dynamicProxyData->throwableClass = "java/lang/IllegalStateException"; dynamicProxyData->throwableMessage = dynamicProxyData->methodName + " is not a function"; dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } fn = v8::Function::Cast(*fnObj); if(dynamicProxyData->args) { v8Args = v8::Array::Cast(*javaArrayToV8(dynamicProxyData->java, env, dynamicProxyData->args)); argc = v8Args->Length(); } else { argc = 0; } argv = new v8::Handle<:value>[argc]; for(i=0; iGet(i); } v8::TryCatch tryCatch; v8Result = fn->Call(dynamicProxyDataFunctions, argc, argv); delete[] argv; if (tryCatch.HasCaught()) { dynamicProxyData->throwableClass = "node/NodeJsException"; v8::String::Utf8Value stackTrace(tryCatch.StackTrace()); if (stackTrace.length() > 0) { dynamicProxyData->throwableMessage = std::string(*stackTrace); } else { v8::String::Utf8Value exception(tryCatch.Exception()); dynamicProxyData->throwableMessage = std::string(*exception); } tryCatch.Reset(); dynamicProxyData->done = DYNAMIC_PROXY_JS_ERROR; return; } if(!dynamicProxyDataVerify(dynamicProxyData)) { return; } javaResult = v8ToJava(env, v8Result); if(javaResult == NULL) { dynamicProxyData->result = NULL; } else { dynamicProxyData->result = env->NewGlobalRef(javaResult); } dynamicProxyData->done = true; } void throwNewThrowable(JNIEnv* env, const char * excClassName, std::string msg) { jclass newExcCls = env->FindClass(excClassName); jthrowable throwable = env->ExceptionOccurred(); if (throwable != NULL) { env->Throw(throwable); // this should only be Errors, according to the docs } env->ThrowNew(newExcCls, msg.c_str()); } JNIEXPORT jobject JNICALL Java_node_NodeDynamicProxyClass_callJs(JNIEnv *env, jobject src, jlong ptr, jobject method, jobjectArray args) { long myThreadId = my_getThreadId(); bool hasArgsGlobalRef = false; // args needs to be global, you can't send env across thread boundaries DynamicProxyData* dynamicProxyData = (DynamicProxyData*)ptr; dynamicProxyData->args = args; dynamicProxyData->done = false; dynamicProxyData->result = NULL; dynamicProxyData->throwableClass = ""; dynamicProxyData->throwableMessage = ""; jclass methodClazz = env->FindClass("java/lang/reflect/Method"); jmethodID method_getName = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;"); dynamicProxyData->methodName = javaObjectToString(env, env->CallObjectMethod(method, method_getName)); assert(!env->ExceptionCheck()); uv_work_t* req = new uv_work_t(); req->data = dynamicProxyData; if(myThreadId == v8ThreadId) { #if NODE_MINOR_VERSION >= 10 EIO_AfterCallJs(req, 0); #else EIO_AfterCallJs(req); #endif } else { if (args) { // if args is not null and we have to kick this across the thread boundary, make it a global ref dynamicProxyData->args = (jobjectArray) env->NewGlobalRef(args); hasArgsGlobalRef = true; } uv_queue_work(uv_default_loop(), req, EIO_CallJs, (uv_after_work_cb)EIO_AfterCallJs); while(!dynamicProxyData->done) { my_sleep(100); } } if(!dynamicProxyDataVerify(dynamicProxyData)) { throwNewThrowable(env, "java/lang/IllegalStateException", "dynamicProxyData was corrupted"); } if(hasArgsGlobalRef) { env->DeleteGlobalRef(dynamicProxyData->args); } if (dynamicProxyData->done == DYNAMIC_PROXY_JS_ERROR) { throwNewThrowable(env, dynamicProxyData->throwableClass.c_str(), dynamicProxyData->throwableMessage); } jobject result = NULL; if(dynamicProxyData->result) { // need to retain a local ref so that we can return it, otherwise the returned object gets corrupted result = env->NewLocalRef(dynamicProxyData->result); env->DeleteGlobalRef(dynamicProxyData->result); } return result; } JNIEXPORT void JNICALL Java_node_NodeDynamicProxyClass_unref(JNIEnv *env, jobject src, jlong ptr) { DynamicProxyData* dynamicProxyData = (DynamicProxyData*)ptr; unref(dynamicProxyData); }