#include "javaObject.h" #include "java.h" #include "utils.h" #include /*static*/ v8::Persistent<:functiontemplate> JavaObject::s_ct; /*static*/ void JavaObject::Init(v8::Handle<:object> target) { v8::HandleScope scope; v8::Local<:functiontemplate> t = v8::FunctionTemplate::New(); s_ct = v8::Persistent<:functiontemplate>::New(t); s_ct->InstanceTemplate()->SetInternalFieldCount(1); s_ct->SetClassName(v8::String::NewSymbol("JavaObject")); target->Set(v8::String::NewSymbol("JavaObject"), s_ct->GetFunction()); } /*static*/ v8::Local<:object> JavaObject::New(Java *java, jobject obj) { v8::HandleScope scope; JNIEnv *env = java->getJavaEnv(); PUSH_LOCAL_JAVA_FRAME(); v8::Local<:function> ctor = s_ct->GetFunction(); v8::Local<:object> javaObjectObj = ctor->NewInstance(); JavaObject *self = new JavaObject(java, obj); self->Wrap(javaObjectObj); std::list methods; javaReflectionGetMethods(env, self->m_class, &methods); jclass methodClazz = env->FindClass("java/lang/reflect/Method"); jmethodID method_getName = env->GetMethodID(methodClazz, "getName", "()Ljava/lang/String;"); for(std::list::iterator it = methods.begin(); it != methods.end(); it++) { jstring methodNameJava = (jstring)env->CallObjectMethod(*it, method_getName); std::string methodNameStr = javaToString(env, methodNameJava); v8::Handle<:string> methodName = v8::String::New(methodNameStr.c_str()); v8::Local<:functiontemplate> methodCallTemplate = v8::FunctionTemplate::New(methodCall, methodName); javaObjectObj->Set(methodName, methodCallTemplate->GetFunction()); v8::Handle<:string> methodNameSync = v8::String::New((methodNameStr + "Sync").c_str()); v8::Local<:functiontemplate> methodCallSyncTemplate = v8::FunctionTemplate::New(methodCallSync, methodName); javaObjectObj->Set(methodNameSync, methodCallSyncTemplate->GetFunction()); env->DeleteLocalRef(methodNameJava); env->DeleteLocalRef(*it); } std::list fields; javaReflectionGetFields(env, self->m_class, &fields); jclass fieldClazz = env->FindClass("java/lang/reflect/Field"); jmethodID field_getName = env->GetMethodID(fieldClazz, "getName", "()Ljava/lang/String;"); for(std::list::iterator it = fields.begin(); it != fields.end(); it++) { jstring fieldNameJava = (jstring)env->CallObjectMethod(*it, field_getName); std::string fieldNameStr = javaToString(env, fieldNameJava); v8::Handle<:string> fieldName = v8::String::New(fieldNameStr.c_str()); javaObjectObj->SetAccessor(fieldName, fieldGetter, fieldSetter); env->DeleteLocalRef(fieldNameJava); env->DeleteLocalRef(*it); } env->DeleteLocalRef(obj); POP_LOCAL_JAVA_FRAME(); return scope.Close(javaObjectObj); } JavaObject::JavaObject(Java *java, jobject obj) { m_java = java; JNIEnv *env = m_java->getJavaEnv(); m_obj = env->NewGlobalRef(obj); m_class = (jclass)env->NewGlobalRef(env->GetObjectClass(obj)); } JavaObject::~JavaObject() { JNIEnv *env = m_java->getJavaEnv(); jclass nodeDynamicProxyClass = env->FindClass("node/NodeDynamicProxyClass"); if(env->IsInstanceOf(m_obj, nodeDynamicProxyClass)) { jfieldID ptrField = env->GetFieldID(nodeDynamicProxyClass, "ptr", "J"); DynamicProxyData* proxyData = (DynamicProxyData*)(long)env->GetLongField(m_obj, ptrField); if(dynamicProxyDataVerify(proxyData)) { delete proxyData; } } env->DeleteGlobalRef(m_obj); env->DeleteGlobalRef(m_class); } /*static*/ v8::Handle<:value> JavaObject::methodCall(const v8::Arguments& args) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap(args.This()); JNIEnv *env = self->m_java->getJavaEnv(); PUSH_LOCAL_JAVA_FRAME(); v8::String::AsciiValue methodName(args.Data()); std::string methodNameStr = *methodName; int argsStart = 0; int argsEnd = args.Length(); // arguments ARGS_BACK_CALLBACK(); if(!callbackProvided && methodNameStr == "toString") { POP_LOCAL_JAVA_FRAME(); return methodCallSync(args); } jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs); if(method == NULL) { EXCEPTION_CALL_CALLBACK("Could not find method " m_java, self, method, methodArgs, callback); baton->run(); env->DeleteLocalRef(methodArgs); env->DeleteLocalRef(method); POP_LOCAL_JAVA_FRAME(); END_CALLBACK_FUNCTION("\"Method '" JavaObject::methodCallSync(const v8::Arguments& args) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap(args.This()); JNIEnv *env = self->m_java->getJavaEnv(); PUSH_LOCAL_JAVA_FRAME(); v8::String::AsciiValue methodName(args.Data()); std::string methodNameStr = *methodName; int argsStart = 0; int argsEnd = args.Length(); jobjectArray methodArgs = v8ToJava(env, args, argsStart, argsEnd); jobject method = javaFindMethod(env, self->m_class, methodNameStr, methodArgs); if(method == NULL) { std::ostringstream errStr; errStr ex = javaExceptionToV8(env, errStr.str()); POP_LOCAL_JAVA_FRAME(); return ThrowException(ex); } // run v8::Handle<:value> callback = v8::Object::New(); InstanceMethodCallBaton* baton = new InstanceMethodCallBaton(self->m_java, self, method, methodArgs, callback); v8::Handle<:value> result = baton->runSync(); delete baton; POP_LOCAL_JAVA_FRAME(); return scope.Close(result); } /*static*/ v8::Handle<:value> JavaObject::fieldGetter(v8::Local<:string> property, const v8::AccessorInfo& info) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap(info.This()); JNIEnv *env = self->m_java->getJavaEnv(); PUSH_LOCAL_JAVA_FRAME(); v8::String::AsciiValue propertyCStr(property); std::string propertyStr = *propertyCStr; jobject field = javaFindField(env, self->m_class, propertyStr); if(field == NULL) { std::ostringstream errStr; errStr ex = javaExceptionToV8(env, errStr.str()); POP_LOCAL_JAVA_FRAME(); return ThrowException(ex); } jclass fieldClazz = env->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, self->m_obj); if(env->ExceptionOccurred()) { std::ostringstream errStr; errStr ex = javaExceptionToV8(env, errStr.str()); POP_LOCAL_JAVA_FRAME(); return ThrowException(ex); } v8::Handle<:value> result = javaToV8(self->m_java, env, val); env->DeleteLocalRef(fieldClazz); env->DeleteLocalRef(field); env->DeleteLocalRef(val); POP_LOCAL_JAVA_FRAME(); return scope.Close(result); } /*static*/ void JavaObject::fieldSetter(v8::Local<:string> property, v8::Local<:value> value, const v8::AccessorInfo& info) { v8::HandleScope scope; JavaObject* self = node::ObjectWrap::Unwrap(info.This()); JNIEnv *env = self->m_java->getJavaEnv(); PUSH_LOCAL_JAVA_FRAME(); jobject newValue = v8ToJava(env, value); v8::String::AsciiValue propertyCStr(property); std::string propertyStr = *propertyCStr; jobject field = javaFindField(env, self->m_class, propertyStr); if(field == NULL) { std::ostringstream errStr; errStr ex = javaExceptionToV8(env, errStr.str()); POP_LOCAL_JAVA_FRAME(); ThrowException(ex); return; } jclass fieldClazz = env->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, self->m_obj, newValue); if(env->ExceptionOccurred()) { std::ostringstream errStr; errStr ex = javaExceptionToV8(env, errStr.str()); POP_LOCAL_JAVA_FRAME(); ThrowException(ex); return; } POP_LOCAL_JAVA_FRAME(); }