Home | History | Annotate | Download | only in java
      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