Browse Source

added a JniCache objectet for caching jclass, jmethodID, and jfieldID objects

Grant Limberg 10 years ago
parent
commit
079d248eab

+ 1 - 0
java/CMakeLists.txt

@@ -43,6 +43,7 @@ set(src_files
     ../osdep/OSUtils.cpp
     jni/com_zerotierone_sdk_Node.cpp
     jni/ZT1_jniutils.cpp
+    jni/ZT1_jnicache.cpp
     )
 
 set(include_dirs

+ 2 - 1
java/jni/Android.mk

@@ -38,6 +38,7 @@ LOCAL_SRC_FILES := \
 # JNI Files
 LOCAL_SRC_FILES += \
 	com_zerotierone_sdk_Node.cpp \
-	ZT1_jniutils.cpp
+	ZT1_jniutils.cpp \
+	ZT1_jnicache.cpp
 
 include $(BUILD_SHARED_LIBRARY)

+ 242 - 0
java/jni/ZT1_jnicache.cpp

@@ -0,0 +1,242 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015  ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include "ZT1_jnicache.h"
+#include "ZT1_jniutils.h"
+
+JniCache::JniCache()
+    : m_jvm(NULL)
+    , m_classes()
+    , m_fields()
+    , m_staticFields()
+    , m_methods()
+    , m_staticMethods()
+{
+    LOGD("JNI Cache Created");
+}
+
+JniCache::JniCache(JavaVM *jvm)
+    : m_jvm(jvm)
+    , m_classes()
+    , m_fields()
+    , m_staticFields()
+    , m_methods()
+    , m_staticMethods()
+{
+    LOGD("JNI Cache Created");
+}
+
+JniCache::~JniCache()
+{
+    LOGD("JNI Cache Destroyed");
+    clearCache();
+}
+
+void JniCache::clearCache()
+{
+    if(m_jvm)
+    {
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+            return;
+
+        for(ClassMap::iterator iter = m_classes.begin(), end = m_classes.end();
+            iter != end; ++iter)
+        {
+            env->DeleteGlobalRef(iter->second);
+        }
+    }
+
+    m_classes.clear();
+    m_fields.clear();
+    m_staticFields.clear();
+    m_methods.clear();
+    m_staticMethods.clear();
+}
+
+void JniCache::setJavaVM(JavaVM *jvm)
+{ 
+    LOGD("Assigned JVM to object");
+    m_jvm = jvm; 
+}
+
+
+jclass JniCache::findClass(const std::string &name)
+{
+    if(!m_jvm)
+        return NULL;
+
+    ClassMap::iterator found = m_classes.find(name);
+
+    if(found == m_classes.end())
+    {
+        // get the class from the JVM
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+        {
+            LOGE("Error retreiving JNI Environment");
+            return NULL;
+        }
+
+        jclass localCls = env->FindClass(name.c_str());
+        if(env->ExceptionCheck())
+        {
+            LOGE("Error finding class: %s", name.c_str());
+            return NULL;
+        }
+
+        jclass cls = (jclass)env->NewGlobalRef(localCls);
+
+        m_classes.insert(std::make_pair(name, cls));
+
+        return cls;
+    }
+
+    LOGD("Returning cached %s", name.c_str());
+    return found->second;
+}
+
+
+jmethodID JniCache::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
+{
+    if(!m_jvm)
+        return NULL;
+
+    std::string id = methodName + methodSig;
+
+    MethodMap::iterator found = m_methods.find(id);
+    if(found == m_methods.end())
+    {
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+        {
+            return NULL;
+        }
+
+        jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str());
+        if(env->ExceptionCheck())
+        {
+            return NULL;
+        }
+
+        m_methods.insert(std::make_pair(id, mid));
+
+        return mid;
+    }
+
+    return found->second;
+}
+
+jmethodID JniCache::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
+{
+    if(!m_jvm)
+        return NULL;
+
+    std::string id = methodName + methodSig;
+
+    MethodMap::iterator found = m_staticMethods.find(id);
+    if(found == m_staticMethods.end())
+    {
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+        {
+            return NULL;
+        }
+
+        jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str());
+        if(env->ExceptionCheck())
+        {
+            return NULL;
+        }
+
+        m_staticMethods.insert(std::make_pair(id, mid));
+
+        return mid;
+    }
+
+    return found->second;
+}
+
+jfieldID JniCache::findField(jclass cls, const std::string &fieldName, const std::string &typeStr)
+{
+    if(!m_jvm)
+        return NULL;
+
+    std::string id = fieldName + typeStr;
+
+    FieldMap::iterator found = m_fields.find(id);
+    if(found == m_fields.end())
+    {
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+        {
+            return NULL;
+        }
+
+        jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str());
+        if(env->ExceptionCheck())
+        {
+            return NULL;
+        }
+
+        m_fields.insert(std::make_pair(id, fid));
+
+        return fid;
+    }
+
+    return found->second;
+}
+
+jfieldID JniCache::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr)
+{
+    if(!m_jvm)
+        return NULL;
+
+    std::string id = fieldName + typeStr;
+
+    FieldMap::iterator found = m_staticFields.find(id);
+    if(found == m_staticFields.end())
+    {
+        JNIEnv *env = NULL;
+        if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
+        {
+            return NULL;
+        }
+
+        jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str());
+        if(env->ExceptionCheck())
+        {
+            return NULL;
+        }
+
+        m_staticFields.insert(std::make_pair(id, fid));
+
+        return fid;
+    }
+
+    return found->second;
+}

+ 65 - 0
java/jni/ZT1_jnicache.h

@@ -0,0 +1,65 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015  ZeroTier, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT1_JNICACHE_H_
+#define ZT1_JNICACHE_H_
+
+#include <jni.h>
+#include <map>
+#include <string>
+
+
+
+class JniCache {
+public:
+    JniCache();
+    JniCache(JavaVM *jvm);
+    ~JniCache();
+
+    void setJavaVM(JavaVM *jvm);
+    void clearCache();
+
+    jclass findClass(const std::string &name);
+    jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
+    jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
+    jfieldID findField(jclass cls, const std::string &fieldName, const std::string &typeStr);
+    jfieldID findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr);
+private:
+    typedef std::map<std::string, jmethodID> MethodMap;
+    typedef std::map<std::string, jfieldID> FieldMap;
+    typedef std::map<std::string, jclass> ClassMap;
+
+    JavaVM *m_jvm;
+    ClassMap m_classes;
+    FieldMap m_fields;
+    FieldMap m_staticFields;
+    MethodMap m_methods;
+    MethodMap m_staticMethods;
+
+};
+
+#endif

+ 3 - 0
java/jni/ZT1_jniutils.cpp

@@ -1,4 +1,5 @@
 #include "ZT1_jniutils.h"
+#include "ZT1_jnicache.h"
 #include <string>
 #include <assert.h>
 
@@ -6,6 +7,8 @@
 extern "C" {
 #endif
 
+extern JniCache cache;
+
 jobject createResultObject(JNIEnv *env, ZT1_ResultCode code)
 {
     jclass resultClass = NULL;

+ 18 - 2
java/jni/com_zerotierone_sdk_Node.cpp

@@ -27,6 +27,7 @@
 
 #include "com_zerotierone_sdk_Node.h"
 #include "ZT1_jniutils.h"
+#include "ZT1_jnicache.h"
 
 #include <ZeroTierOne.h>
 
@@ -39,6 +40,9 @@
 extern "C" {
 #endif
 
+// global static JNI Cache Object
+static JniCache cache;
+
 namespace {
     struct JniRef
     {
@@ -322,7 +326,7 @@ namespace {
         LOGD("Calling onDataStoreGet(%s, %p, %lu, %p)",
             objectName, buffer, bufferIndex, objectSizeObj);
 
-        long retval = env->CallLongMethod(
+        long retval = (long)env->CallLongMethod(
             ref->dataStoreGetListener, dataStoreGetCallbackMethod, 
             nameStr, bufferObj, (jlong)bufferIndex, objectSizeObj);
 
@@ -446,6 +450,18 @@ namespace {
     }
 }
 
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) 
+{
+    cache.setJavaVM(vm);
+    return JNI_VERSION_1_6;
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
+{
+    cache.clearCache();
+}
+
+
 /*
  * Class:     com_zerotierone_sdk_Node
  * Method:    node_init
@@ -905,7 +921,7 @@ JNIEXPORT jobject JNICALL Java_com_zerotierone_sdk_Node_multicastSubscribe(
 
     uint64_t nwid = (uint64_t)in_nwid;
     uint64_t multicastGroup = (uint64_t)in_multicastGroup;
-    uint64_t multicastAdi = (uint64_t)in_multicastAdi;
+    unsigned long multicastAdi = (unsigned long)in_multicastAdi;
 
     ZT1_ResultCode rc = ZT1_Node_multicastSubscribe(
         node, nwid, multicastGroup, multicastAdi);