You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
5.7 KiB
185 lines
5.7 KiB
/* ----------------------------------------------------------------------------- |
|
* See the LICENSE file for information on copyright, usage and redistribution |
|
* of SWIG, and the README file for authors - http://www.swig.org/release.html. |
|
* |
|
* director.swg |
|
* |
|
* This file contains support for director classes that proxy |
|
* method calls from C++ to Java extensions. |
|
* ----------------------------------------------------------------------------- */ |
|
|
|
#ifdef __cplusplus |
|
|
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
#include <iostream> |
|
#endif |
|
|
|
namespace Swig { |
|
/* Java object wrapper */ |
|
class JObjectWrapper { |
|
public: |
|
JObjectWrapper() : jthis_(NULL), weak_global_(true) { |
|
} |
|
|
|
~JObjectWrapper() { |
|
jthis_ = NULL; |
|
weak_global_ = true; |
|
} |
|
|
|
bool set(JNIEnv *jenv, jobject jobj, bool mem_own, bool weak_global) { |
|
if (!jthis_) { |
|
weak_global_ = weak_global; |
|
if (jobj) |
|
jthis_ = ((weak_global_ || !mem_own) ? jenv->NewWeakGlobalRef(jobj) : jenv->NewGlobalRef(jobj)); |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> " << jthis_ << std::endl; |
|
#endif |
|
return true; |
|
} else { |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "JObjectWrapper::set(" << jobj << ", " << (weak_global ? "weak_global" : "global_ref") << ") -> already set" << std::endl; |
|
#endif |
|
return false; |
|
} |
|
} |
|
|
|
jobject get(JNIEnv *jenv) const { |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "JObjectWrapper::get("; |
|
if (jthis_) |
|
std::cout << jthis_; |
|
else |
|
std::cout << "null"; |
|
std::cout << ") -> return new local ref" << std::endl; |
|
#endif |
|
return (jthis_ ? jenv->NewLocalRef(jthis_) : jthis_); |
|
} |
|
|
|
void release(JNIEnv *jenv) { |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "JObjectWrapper::release(" << jthis_ << "): " << (weak_global_ ? "weak global ref" : "global ref") << std::endl; |
|
#endif |
|
if (jthis_) { |
|
if (weak_global_) { |
|
if (jenv->IsSameObject(jthis_, NULL) == JNI_FALSE) |
|
jenv->DeleteWeakGlobalRef((jweak)jthis_); |
|
} else |
|
jenv->DeleteGlobalRef(jthis_); |
|
} |
|
|
|
jthis_ = NULL; |
|
weak_global_ = true; |
|
} |
|
|
|
jobject peek() { |
|
return jthis_; |
|
} |
|
|
|
/* Java proxy releases ownership of C++ object, C++ object is now |
|
responsible for destruction (creates NewGlobalRef to pin Java |
|
proxy) */ |
|
void java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { |
|
if (take_or_release) { /* Java takes ownership of C++ object's lifetime. */ |
|
if (!weak_global_) { |
|
jenv->DeleteGlobalRef(jthis_); |
|
jthis_ = jenv->NewWeakGlobalRef(jself); |
|
weak_global_ = true; |
|
} |
|
} else { /* Java releases ownership of C++ object's lifetime */ |
|
if (weak_global_) { |
|
jenv->DeleteWeakGlobalRef((jweak)jthis_); |
|
jthis_ = jenv->NewGlobalRef(jself); |
|
weak_global_ = false; |
|
} |
|
} |
|
} |
|
|
|
private: |
|
/* pointer to Java object */ |
|
jobject jthis_; |
|
/* Local or global reference flag */ |
|
bool weak_global_; |
|
}; |
|
|
|
/* director base class */ |
|
class Director { |
|
/* pointer to Java virtual machine */ |
|
JavaVM *swig_jvm_; |
|
|
|
protected: |
|
#if defined (_MSC_VER) && (_MSC_VER<1300) |
|
class JNIEnvWrapper; |
|
friend class JNIEnvWrapper; |
|
#endif |
|
/* Utility class for managing the JNI environment */ |
|
class JNIEnvWrapper { |
|
const Director *director_; |
|
JNIEnv *jenv_; |
|
public: |
|
JNIEnvWrapper(const Director *director) : director_(director), jenv_(0) { |
|
director_->swig_jvm_->AttachCurrentThread((void **) &jenv_, NULL); |
|
} |
|
~JNIEnvWrapper() { |
|
// Some JVMs, eg JDK 1.4.2 and lower on Solaris have a bug and crash with the DetachCurrentThread call. |
|
// However, without this call, the JVM hangs on exit when the thread was not created by the JVM and creates a memory leak. |
|
#if !defined(SWIG_JAVA_NO_DETACH_CURRENT_THREAD) |
|
director_->swig_jvm_->DetachCurrentThread(); |
|
#endif |
|
} |
|
JNIEnv *getJNIEnv() const { |
|
return jenv_; |
|
} |
|
}; |
|
|
|
/* Java object wrapper */ |
|
JObjectWrapper swig_self_; |
|
|
|
/* Disconnect director from Java object */ |
|
void swig_disconnect_director_self(const char *disconn_method) { |
|
JNIEnvWrapper jnienv(this) ; |
|
JNIEnv *jenv = jnienv.getJNIEnv() ; |
|
jobject jobj = swig_self_.peek(); |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "Swig::Director::disconnect_director_self(" << jobj << ")" << std::endl; |
|
#endif |
|
if (jobj && jenv->IsSameObject(jobj, NULL) == JNI_FALSE) { |
|
jmethodID disconn_meth = jenv->GetMethodID(jenv->GetObjectClass(jobj), disconn_method, "()V"); |
|
if (disconn_meth) { |
|
#if defined(DEBUG_DIRECTOR_OWNED) |
|
std::cout << "Swig::Director::disconnect_director_self upcall to " << disconn_method << std::endl; |
|
#endif |
|
jenv->CallVoidMethod(jobj, disconn_meth); |
|
} |
|
} |
|
} |
|
|
|
public: |
|
Director(JNIEnv *jenv) : swig_jvm_((JavaVM *) NULL), swig_self_() { |
|
/* Acquire the Java VM pointer */ |
|
jenv->GetJavaVM(&swig_jvm_); |
|
} |
|
|
|
virtual ~Director() { |
|
JNIEnvWrapper jnienv(this) ; |
|
JNIEnv *jenv = jnienv.getJNIEnv() ; |
|
swig_self_.release(jenv); |
|
} |
|
|
|
bool swig_set_self(JNIEnv *jenv, jobject jself, bool mem_own, bool weak_global) { |
|
return swig_self_.set(jenv, jself, mem_own, weak_global); |
|
} |
|
|
|
jobject swig_get_self(JNIEnv *jenv) const { |
|
return swig_self_.get(jenv); |
|
} |
|
|
|
// Change C++ object's ownership, relative to Java |
|
void swig_java_change_ownership(JNIEnv *jenv, jobject jself, bool take_or_release) { |
|
swig_self_.java_change_ownership(jenv, jself, take_or_release); |
|
} |
|
}; |
|
} |
|
|
|
#endif /* __cplusplus */ |
|
|
|
|
|
|