diff options
Diffstat (limited to 'share/swig/3.0.12/java/director.swg')
-rw-r--r-- | share/swig/3.0.12/java/director.swg | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/share/swig/3.0.12/java/director.swg b/share/swig/3.0.12/java/director.swg new file mode 100644 index 0000000..355e62d --- /dev/null +++ b/share/swig/3.0.12/java/director.swg @@ -0,0 +1,413 @@ +/* ----------------------------------------------------------------------------- + * director.swg + * + * This file contains support for director classes so that Java proxy + * methods can be called from C++. + * ----------------------------------------------------------------------------- */ + +#if defined(DEBUG_DIRECTOR_OWNED) || defined(DEBUG_DIRECTOR_EXCEPTION) +#include <iostream> +#endif + +#include <exception> + +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 || !mem_own; // hold as weak global if explicitly requested or not owned + if (jobj) + jthis_ = weak_global_ ? 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; + } + + /* Only call peek if you know what you are doing wrt to weak/global references */ + 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_; + }; + + /* Local JNI reference deleter */ + class LocalRefGuard { + JNIEnv *jenv_; + jobject jobj_; + + // non-copyable + LocalRefGuard(const LocalRefGuard &); + LocalRefGuard &operator=(const LocalRefGuard &); + public: + LocalRefGuard(JNIEnv *jenv, jobject jobj): jenv_(jenv), jobj_(jobj) {} + ~LocalRefGuard() { + if (jobj_) + jenv_->DeleteLocalRef(jobj_); + } + }; + + /* 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_; + int env_status; + public: + JNIEnvWrapper(const Director *director) : director_(director), jenv_(0), env_status(0) { +#if defined(__ANDROID__) + JNIEnv **jenv = &jenv_; +#else + void **jenv = (void **)&jenv_; +#endif + env_status = director_->swig_jvm_->GetEnv((void **)&jenv_, JNI_VERSION_1_2); +#if defined(SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON) + // Attach a daemon thread to the JVM. Useful when the JVM should not wait for + // the thread to exit upon shutdown. Only for jdk-1.4 and later. + director_->swig_jvm_->AttachCurrentThreadAsDaemon(jenv, NULL); +#else + director_->swig_jvm_->AttachCurrentThread(jenv, NULL); +#endif + } + ~JNIEnvWrapper() { +#if !defined(SWIG_JAVA_NO_DETACH_CURRENT_THREAD) + // 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 (env_status == JNI_EDETACHED) + 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_.get(jenv); + LocalRefGuard ref_deleter(jenv, jobj); +#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); + } + }; + + // Zero initialized bool array + template<size_t N> class BoolArray { + bool array_[N]; + public: + BoolArray() { + memset(array_, 0, sizeof(array_)); + } + bool& operator[](size_t n) { + return array_[n]; + } + bool operator[](size_t n) const { + return array_[n]; + } + }; + + // Utility classes and functions for exception handling. + + // Simple holder for a Java string during exception handling, providing access to a c-style string + class JavaString { + public: + JavaString(JNIEnv *jenv, jstring jstr) : jenv_(jenv), jstr_(jstr), cstr_(0) { + if (jenv_ && jstr_) + cstr_ = (const char *) jenv_->GetStringUTFChars(jstr_, NULL); + } + + ~JavaString() { + if (jenv_ && jstr_ && cstr_) + jenv_->ReleaseStringUTFChars(jstr_, cstr_); + } + + const char *c_str(const char *null_string = "null JavaString") const { + return cstr_ ? cstr_ : null_string; + } + + private: + // non-copyable + JavaString(const JavaString &); + JavaString &operator=(const JavaString &); + + JNIEnv *jenv_; + jstring jstr_; + const char *cstr_; + }; + + // Helper class to extract the exception message from a Java throwable + class JavaExceptionMessage { + public: + JavaExceptionMessage(JNIEnv *jenv, jthrowable throwable) : message_(jenv, exceptionMessageFromThrowable(jenv, throwable)) { + } + + const char *message() const { + return message_.c_str("Could not get exception message in JavaExceptionMessage"); + } + + private: + // non-copyable + JavaExceptionMessage(const JavaExceptionMessage &); + JavaExceptionMessage &operator=(const JavaExceptionMessage &); + + // Get exception message by calling Java method Throwable.getMessage() + static jstring exceptionMessageFromThrowable(JNIEnv *jenv, jthrowable throwable) { + jstring jmsg = NULL; + if (jenv && throwable) { + jenv->ExceptionClear(); // Cannot invoke methods with any pending exceptions + jclass throwclz = jenv->GetObjectClass(throwable); + if (throwclz) { + // All Throwable classes have a getMessage() method, so call it to extract the exception message + jmethodID getMessageMethodID = jenv->GetMethodID(throwclz, "getMessage", "()Ljava/lang/String;"); + if (getMessageMethodID) + jmsg = (jstring)jenv->CallObjectMethod(throwable, getMessageMethodID); + } + if (jmsg == NULL && jenv->ExceptionCheck()) + jenv->ExceptionClear(); + } + return jmsg; + } + + JavaString message_; + }; + + // C++ Exception class for handling Java exceptions thrown during a director method Java upcall + class DirectorException : public std::exception { + public: + + // Construct exception from a Java throwable + DirectorException(JNIEnv *jenv, jthrowable throwable) : classname_(0), msg_(0) { + + // Call Java method Object.getClass().getName() to obtain the throwable's class name (delimited by '/') + if (throwable) { + jclass throwclz = jenv->GetObjectClass(throwable); + if (throwclz) { + jclass clzclz = jenv->GetObjectClass(throwclz); + if (clzclz) { + jmethodID getNameMethodID = jenv->GetMethodID(clzclz, "getName", "()Ljava/lang/String;"); + if (getNameMethodID) { + jstring jstr_classname = (jstring)(jenv->CallObjectMethod(throwclz, getNameMethodID)); + // Copy strings, since there is no guarantee that jenv will be active when handled + if (jstr_classname) { + JavaString jsclassname(jenv, jstr_classname); + const char *classname = jsclassname.c_str(0); + if (classname) + classname_ = copypath(classname); + } + } + } + } + } + + JavaExceptionMessage exceptionmsg(jenv, throwable); + msg_ = copystr(exceptionmsg.message()); + } + + // More general constructor for handling as a java.lang.RuntimeException + DirectorException(const char *msg) : classname_(0), msg_(copystr(msg ? msg : "Unspecified DirectorException message")) { + } + + ~DirectorException() throw() { + delete[] classname_; + delete[] msg_; + } + + const char *what() const throw() { + return msg_; + } + + // Reconstruct and raise/throw the Java Exception that caused the DirectorException + // Note that any error in the JNI exception handling results in a Java RuntimeException + void raiseJavaException(JNIEnv *jenv) const { + if (jenv) { + jenv->ExceptionClear(); + + jmethodID ctorMethodID = 0; + jclass throwableclass = 0; + if (classname_) { + throwableclass = jenv->FindClass(classname_); + if (throwableclass) + ctorMethodID = jenv->GetMethodID(throwableclass, "<init>", "(Ljava/lang/String;)V"); + } + + if (ctorMethodID) { + jenv->ThrowNew(throwableclass, what()); + } else { + SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, what()); + } + } + } + + private: + static char *copypath(const char *srcmsg) { + char *target = copystr(srcmsg); + for (char *c=target; *c; ++c) { + if ('.' == *c) + *c = '/'; + } + return target; + } + + static char *copystr(const char *srcmsg) { + char *target = 0; + if (srcmsg) { + size_t msglen = strlen(srcmsg) + 1; + target = new char[msglen]; + strncpy(target, srcmsg, msglen); + } + return target; + } + + const char *classname_; + const char *msg_; + }; + + // Helper method to determine if a Java throwable matches a particular Java class type + SWIGINTERN bool ExceptionMatches(JNIEnv *jenv, jthrowable throwable, const char *classname) { + bool matches = false; + + if (throwable && jenv && classname) { + // Exceptions need to be cleared for correct behavior. + // The caller of ExceptionMatches should restore pending exceptions if desired - + // the caller already has the throwable. + jenv->ExceptionClear(); + + jclass clz = jenv->FindClass(classname); + if (clz) { + jclass classclz = jenv->GetObjectClass(clz); + jmethodID isInstanceMethodID = jenv->GetMethodID(classclz, "isInstance", "(Ljava/lang/Object;)Z"); + if (isInstanceMethodID) { + matches = jenv->CallBooleanMethod(clz, isInstanceMethodID, throwable) != 0; + } + } + +#if defined(DEBUG_DIRECTOR_EXCEPTION) + if (jenv->ExceptionCheck()) { + // Typically occurs when an invalid classname argument is passed resulting in a ClassNotFoundException + JavaExceptionMessage exc(jenv, jenv->ExceptionOccurred()); + std::cout << "Error: ExceptionMatches: class '" << classname << "' : " << exc.message() << std::endl; + } +#endif + } + return matches; + } +} + |