1 /* ----------------------------------------------------------------------------- 2 * director.swg 3 * 4 * This file contains support for director classes that proxy 5 * method calls from C++ to Java extensions. 6 * ----------------------------------------------------------------------------- */ 7 8 #ifdef __cplusplus 9 10 #if defined(DEBUG_DIRECTOR_OWNED) 11 #include <iostream> 12 #endif 13 14 namespace Swig { 15 /* Java object wrapper */ 16 class JObjectWrapper { 17 public: 18 JObjectWrapper() : jthis_(NULL), weak_global_(true) { 19 } 20 21 ~JObjectWrapper() { 22 jthis_ = NULL; 23 weak_global_ = true; 24 } 25 26 bool set(JNIEnv *jenv, jobject jobj, bool mem_own, bool weak_global) { 27 if (!jthis_) { 28 weak_global_ = weak_global || !mem_own; // hold as weak global if explicitly requested or not owned 29 if (jobj) 30 jthis_ = weak_global_ ? jenv->NewWeakGlobalRef(jobj) : jenv->NewGlobalRef(jobj); 31 #if defined(DEBUG_DIRECTOR_OWNED) 32 std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> " << jthis_ << std::endl; 33 #endif 34 return true; 35 } else { 36 #if defined(DEBUG_DIRECTOR_OWNED) 37 std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> already set" << std::endl; 38 #endif 39 return false; 40 } 41 } 42 43 jobject get(JNIEnv *jenv) const { 44 #if defined(DEBUG_DIRECTOR_OWNED) 45 std::cout << "JObjectWrapper::get("; 46 if (jthis_) 47 std::cout << jthis_; 48 else 49 std::cout << "null"; 50 std::cout << ") -> return new local ref" << std::endl; 51 #endif 52 return (jthis_ ? jenv->NewLocalRef(jthis_) : jthis_); 53 } 54 55 void release(JNIEnv *jenv) { 56 #if defined(DEBUG_DIRECTOR_OWNED) 57 std::cout << "JObjectWrapper::release(" << jthis_ << "): " << (weak_global_ ? "weak global ref" : "global ref") << std::endl; 58 #endif 59 if (jthis_) { 60 if (weak_global_) { 61 if (jenv->IsSameObject(jthis_, NULL) == JNI_FALSE) 62 jenv->DeleteWeakGlobalRef((jweak)jthis_); 63 } else 64 jenv->DeleteGlobalRef(jthis_); 65 } 66 67 jthis_ = NULL; 68 weak_global_ = true; 69 } 70 71 /* Only call peek if you know what you are doing wrt to weak/global references */ 72 jobject peek() { 73 return jthis_; 74 } 75 76 /* Java proxy releases ownership of C++ object, C++ object is now 77 responsible for destruction (creates NewGlobalRef to pin Java 78 proxy) */ 79 void java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { 80 if (take_or_release) { /* Java takes ownership of C++ object's lifetime. */ 81 if (!weak_global_) { 82 jenv->DeleteGlobalRef(jthis_); 83 jthis_ = jenv->NewWeakGlobalRef(jself); 84 weak_global_ = true; 85 } 86 } else { /* Java releases ownership of C++ object's lifetime */ 87 if (weak_global_) { 88 jenv->DeleteWeakGlobalRef((jweak)jthis_); 89 jthis_ = jenv->NewGlobalRef(jself); 90 weak_global_ = false; 91 } 92 } 93 } 94 95 private: 96 /* pointer to Java object */ 97 jobject jthis_; 98 /* Local or global reference flag */ 99 bool weak_global_; 100 }; 101 102 /* director base class */ 103 class Director { 104 /* pointer to Java virtual machine */ 105 JavaVM *swig_jvm_; 106 107 protected: 108 #if defined (_MSC_VER) && (_MSC_VER<1300) 109 class JNIEnvWrapper; 110 friend class JNIEnvWrapper; 111 #endif 112 /* Utility class for managing the JNI environment */ 113 class JNIEnvWrapper { 114 const Director *director_; 115 JNIEnv *jenv_; 116 int env_status; 117 public: 118 JNIEnvWrapper(const Director *director) : director_(director), jenv_(0), env_status(0) { 119 #if defined(__ANDROID__) 120 JNIEnv **jenv = &jenv_; 121 #else 122 void **jenv = (void **)&jenv_; 123 #endif 124 env_status = director_->swig_jvm_->GetEnv((void **)&jenv_, JNI_VERSION_1_2); 125 #if defined(SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON) 126 // Attach a daemon thread to the JVM. Useful when the JVM should not wait for 127 // the thread to exit upon shutdown. Only for jdk-1.4 and later. 128 director_->swig_jvm_->AttachCurrentThreadAsDaemon(jenv, NULL); 129 #else 130 director_->swig_jvm_->AttachCurrentThread(jenv, NULL); 131 #endif 132 } 133 ~JNIEnvWrapper() { 134 #if !defined(SWIG_JAVA_NO_DETACH_CURRENT_THREAD) 135 // Some JVMs, eg jdk-1.4.2 and lower on Solaris have a bug and crash with the DetachCurrentThread call. 136 // However, without this call, the JVM hangs on exit when the thread was not created by the JVM and creates a memory leak. 137 if (env_status == JNI_EDETACHED) 138 director_->swig_jvm_->DetachCurrentThread(); 139 #endif 140 } 141 JNIEnv *getJNIEnv() const { 142 return jenv_; 143 } 144 }; 145 146 /* Java object wrapper */ 147 JObjectWrapper swig_self_; 148 149 /* Disconnect director from Java object */ 150 void swig_disconnect_director_self(const char *disconn_method) { 151 JNIEnvWrapper jnienv(this) ; 152 JNIEnv *jenv = jnienv.getJNIEnv() ; 153 jobject jobj = swig_self_.get(jenv); 154 #if defined(DEBUG_DIRECTOR_OWNED) 155 std::cout << "Swig::Director::disconnect_director_self(" << jobj << ")" << std::endl; 156 #endif 157 if (jobj && jenv->IsSameObject(jobj, NULL) == JNI_FALSE) { 158 jmethodID disconn_meth = jenv->GetMethodID(jenv->GetObjectClass(jobj), disconn_method, "()V"); 159 if (disconn_meth) { 160 #if defined(DEBUG_DIRECTOR_OWNED) 161 std::cout << "Swig::Director::disconnect_director_self upcall to " << disconn_method << std::endl; 162 #endif 163 jenv->CallVoidMethod(jobj, disconn_meth); 164 } 165 } 166 jenv->DeleteLocalRef(jobj); 167 } 168 169 public: 170 Director(JNIEnv *jenv) : swig_jvm_((JavaVM *) NULL), swig_self_() { 171 /* Acquire the Java VM pointer */ 172 jenv->GetJavaVM(&swig_jvm_); 173 } 174 175 virtual ~Director() { 176 JNIEnvWrapper jnienv(this) ; 177 JNIEnv *jenv = jnienv.getJNIEnv() ; 178 swig_self_.release(jenv); 179 } 180 181 bool swig_set_self(JNIEnv *jenv, jobject jself, bool mem_own, bool weak_global) { 182 return swig_self_.set(jenv, jself, mem_own, weak_global); 183 } 184 185 jobject swig_get_self(JNIEnv *jenv) const { 186 return swig_self_.get(jenv); 187 } 188 189 // Change C++ object's ownership, relative to Java 190 void swig_java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { 191 swig_self_.java_change_ownership(jenv, jself, take_or_release); 192 } 193 }; 194 } 195 196 #endif /* __cplusplus */ 197 198 199