diff options
author | Sven Gothel <[email protected]> | 2020-10-16 04:31:06 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2020-10-16 04:31:06 +0200 |
commit | 828de1e67e91e80612ab63fd852c1bb0f83d2a18 (patch) | |
tree | 09e0f232e7f923ba80ff3c6cd1121d5afd345aea /java | |
parent | 2573569b759e9d6ce6fe99e23a3393c08966d62b (diff) |
Extract common C++ Support Library inclusive Java JNI Binding to sub-project jaucpp, namespace jau
Diffstat (limited to 'java')
-rw-r--r-- | java/jni/BluetoothFactory.cxx | 3 | ||||
-rw-r--r-- | java/jni/BluetoothUtils.cxx | 9 | ||||
-rw-r--r-- | java/jni/JNIMem.cxx | 171 | ||||
-rw-r--r-- | java/jni/JNIMem.hpp | 198 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.cxx | 23 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.hpp | 128 | ||||
-rw-r--r-- | java/jni/helper_base.cxx | 290 | ||||
-rw-r--r-- | java/jni/helper_base.hpp | 225 | ||||
-rw-r--r-- | java/jni/tinyb/helper_tinyb.cxx | 2 | ||||
-rw-r--r-- | java/jni/tinyb/helper_tinyb.hpp | 1 |
10 files changed, 42 insertions, 1008 deletions
diff --git a/java/jni/BluetoothFactory.cxx b/java/jni/BluetoothFactory.cxx index f62984c..b8f4520 100644 --- a/java/jni/BluetoothFactory.cxx +++ b/java/jni/BluetoothFactory.cxx @@ -27,9 +27,10 @@ #include "version.h" -#include "JNIMem.hpp" #include "helper_base.hpp" +using namespace jau; + jstring Java_org_tinyb_BluetoothFactory_getNativeAPIVersion(JNIEnv *env, jclass clazz) { try { diff --git a/java/jni/BluetoothUtils.cxx b/java/jni/BluetoothUtils.cxx index 0cf4128..98741e7 100644 --- a/java/jni/BluetoothUtils.cxx +++ b/java/jni/BluetoothUtils.cxx @@ -30,10 +30,9 @@ #include <time.h> -#include "JNIMem.hpp" -#include "helper_base.hpp" +#include <jau/dfa_utf8_decode.hpp> -#include "direct_bt/dfa_utf8_decode.hpp" +#include "helper_base.hpp" static const int64_t NanoPerMilli = 1000000L; static const int64_t MilliPerOne = 1000L; @@ -77,7 +76,7 @@ jstring Java_org_tinyb_BluetoothUtils_decodeUTF8String(JNIEnv *env, jclass clazz if( NULL == buffer_ptr ) { throw std::invalid_argument("GetPrimitiveArrayCritical(byte array) is null"); } - sres = dfa_utf8_decode(buffer_ptr+offset, size); + sres = jau::dfa_utf8_decode(buffer_ptr+offset, size); } - return from_string_to_jstring(env, sres); + return jau::from_string_to_jstring(env, sres); } diff --git a/java/jni/JNIMem.cxx b/java/jni/JNIMem.cxx deleted file mode 100644 index e5b3aaf..0000000 --- a/java/jni/JNIMem.cxx +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Author: Petre Eftime <[email protected]> - * Copyright (c) 2016 Intel Corporation. - * - * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <cstdio> - -#include "JNIMem.hpp" - -#include "dbt_debug.hpp" - - -JavaVM* vm; -thread_local JNIEnvContainer jni_env; - -jint JNI_OnLoad(JavaVM *initVM, void *reserved) { - (void)reserved; // warning - vm = initVM; - return JNI_VERSION_1_8; -} - -JNIEnv *JNIEnvContainer::operator*() { - attach(); - return env; -} - -JNIEnv *JNIEnvContainer::operator->() { - attach(); - return env; -} - -JNIEnvContainer::JNIEnvContainer() {} - -JNIEnvContainer::~JNIEnvContainer() { - detach(); -} - -void JNIEnvContainer::attach() { - if (env != nullptr) { - return; - } - JNIEnv *newEnv = nullptr; - int envRes; - - envRes = vm->GetEnv((void **) &env, JNI_VERSION_1_8) ; - if( JNI_EDETACHED == envRes ) { - envRes = vm->AttachCurrentThreadAsDaemon((void**) &newEnv, NULL); - if( JNI_OK != envRes ) { - throw direct_bt::RuntimeException("Attach to VM failed", E_FILE_LINE); - } - env = newEnv; - } else if( JNI_OK != envRes ) { - throw direct_bt::RuntimeException("GetEnv of VM failed", E_FILE_LINE); - } - if (env==NULL) { - throw direct_bt::RuntimeException("GetEnv of VM is NULL", E_FILE_LINE); - } - needsDetach = NULL != newEnv; -} - -void JNIEnvContainer::detach() { - if (env == nullptr) { - return; - } - if( needsDetach ) { - vm->DetachCurrentThread(); - } - env = nullptr; - needsDetach = false; -} - -JNIGlobalRef::JNIGlobalRef() noexcept { - this->object = nullptr; - DBG_JNI_PRINT("JNIGlobalRef::def_ctor nullptr"); -} - -JNIGlobalRef::JNIGlobalRef(jobject object) { - if( nullptr == object ) { - throw direct_bt::RuntimeException("JNIGlobalRef ctor null jobject", E_FILE_LINE); - } - this->object = jni_env->NewGlobalRef(object); - DBG_JNI_PRINT("JNIGlobalRef::def_ctor %p -> %p", object, this->object); -} - -JNIGlobalRef::JNIGlobalRef(const JNIGlobalRef &o) { - if( nullptr == o.object ) { - throw direct_bt::RuntimeException("Other JNIGlobalRef jobject is null", E_FILE_LINE); - } - object = jni_env->NewGlobalRef(o.object); - DBG_JNI_PRINT("JNIGlobalRef::copy_ctor %p -> %p", o.object, object); -} -JNIGlobalRef::JNIGlobalRef(JNIGlobalRef &&o) noexcept -: object(o.object) { - DBG_JNI_PRINT("JNIGlobalRef::move_ctor %p (nulled) -> %p", o.object, object); - o.object = nullptr; -} -JNIGlobalRef& JNIGlobalRef::operator=(const JNIGlobalRef &o) { - if( &o == this ) { - return *this; - } - JNIEnv * env = *jni_env; - if( nullptr != object ) { // always - env->DeleteGlobalRef(object); - } - if( nullptr == o.object ) { - throw direct_bt::RuntimeException("Other JNIGlobalRef jobject is null", E_FILE_LINE); - } - object = jni_env->NewGlobalRef(o.object); - DBG_JNI_PRINT("JNIGlobalRef::copy_assign %p -> %p", o.object, object); - return *this; -} -JNIGlobalRef& JNIGlobalRef::operator=(JNIGlobalRef &&o) noexcept { - object = o.object; - DBG_JNI_PRINT("JNIGlobalRef::move_assign %p (nulled) -> %p", o.object, object); - o.object = nullptr; - return *this; -} - -JNIGlobalRef::~JNIGlobalRef() noexcept { - try { - JNIEnv * env = *jni_env; - if( nullptr == env ) { - ABORT("JNIGlobalRef dtor null JNIEnv"); - } - DBG_JNI_PRINT("JNIGlobalRef::dtor %p", object); - if( nullptr != object ) { - // due to move ctor and assignment, we accept nullptr object - env->DeleteGlobalRef(object); - } - } catch (std::exception &e) { - fprintf(stderr, "JNIGlobalRef dtor: Caught %s\n", e.what()); - } -} - -void JNIGlobalRef::clear() noexcept { - DBG_JNI_PRINT("JNIGlobalRef::clear %p (nulled) -> null", object); - object = nullptr; -} - -bool JNIGlobalRef::operator==(const JNIGlobalRef& rhs) const noexcept { - if( &rhs == this ) { - DBG_JNI_PRINT("JNIGlobalRef::== true: %p == %p (ptr)", object, rhs.object); - return true; - } - bool res = JNI_TRUE == jni_env->IsSameObject(object, rhs.object); - DBG_JNI_PRINT("JNIGlobalRef::== %d: %p == %p (IsSameObject)", res, object, rhs.object); - return res; -} diff --git a/java/jni/JNIMem.hpp b/java/jni/JNIMem.hpp deleted file mode 100644 index ac6cf11..0000000 --- a/java/jni/JNIMem.hpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Author: Petre Eftime <[email protected]> - * Copyright (c) 2016 Intel Corporation. - * - * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef JNIMEM__HPP_ -#define JNIMEM__HPP_ - -#include <jni.h> -#include <stdexcept> - -#include "BasicTypes.hpp" - -extern JavaVM* vm; - - -/* - * This class provides a lifetime-managed JNIEnv object, which attaches or - * detaches the current thread from the JVM automatically - */ -class JNIEnvContainer { -private: - JNIEnv *env = nullptr; - bool needsDetach = false; - -public: - /* Attaches this thread to the JVM if it is not already attached */ - JNIEnvContainer(); - /* Detaches this thread to the JVM if it is attached */ - ~JNIEnvContainer(); - - /* Provides access to the local thread's JNIEnv object */ - JNIEnv *operator*(); - /* Provides access to the local thread's JNIEnv object's methods */ - JNIEnv *operator->(); - - /* Attaches this thread to the JVM if it is not already attached */ - void attach(); - /* Detaches this thread to the JVM if it is attached */ - void detach(); -}; - -/* Each thread has a local jni_env variable of JNIEnvContainer type */ -extern thread_local JNIEnvContainer jni_env; - -/* - * This class provides a lifetime-managed GlobalRef variable, - * which is automatically deleted when it goes out of scope. - * - * RAII-style acquire and relinquish via destructor - */ -class JNIGlobalRef { -private: - jobject object; - -public: - static inline void check(jobject object, const char* file, int line) { - if( nullptr == object ) { - throw direct_bt::RuntimeException("JNIGlobalRef::check: Null jobject", file, line); - } - } - - /* Creates a GlobalRef using a nullptr for API convenience, lazy assignment. */ - JNIGlobalRef() noexcept; - - /* Creates a GlobalRef from an object passed to it */ - JNIGlobalRef(jobject object); - - JNIGlobalRef(const JNIGlobalRef &o); - JNIGlobalRef(JNIGlobalRef &&o) noexcept; - - JNIGlobalRef& operator=(const JNIGlobalRef &o); - JNIGlobalRef& operator=(JNIGlobalRef &&o) noexcept; - - /* Deletes the stored GlobalRef */ - ~JNIGlobalRef() noexcept; - - /** Clears the java reference, i.e. nulling it, without deleting the global reference via JNI. */ - void clear() noexcept; - - /* Provides access to the stored GlobalRef as an jobject. */ - jobject operator*() noexcept { return object; } - - /* Provides access to the stored GlobalRef as an jobject. */ - jobject getObject() const noexcept { return object; } - /* Provides access to the stored GlobalRef as a jclass. */ - jclass getClass() const noexcept { return (jclass)object; } - - bool operator==(const JNIGlobalRef& rhs) const noexcept; - - bool operator!=(const JNIGlobalRef& rhs) const noexcept - { return !( *this == rhs ); } -}; - -/* - * This class provides a lifetime-managed 'PrimitiveArrayCritical' pinned heap, - * which is automatically released when it goes out of scope. - * - * RAII-style acquire and relinquish via destructor - */ -template <typename T, typename U> -class JNICriticalArray { -public: - enum Mode : jint { - /** Like default 0: If 'isCopy': Update the java array data with the copy and free the copy. */ - UPDATE_AND_RELEASE = 0, - - /** Like JNI_COMMIT: If 'isCopy': Update the java array data with the copy, but do not free the copy. */ - UPDATE_NO_RELEASE = JNI_COMMIT, - - /** Like default JNI_ABORT: If 'isCopy': Do not update the java array data with the copy, but free the copy. */ - NO_UPDATE_AND_RELEASE = JNI_ABORT, - }; - -private: - JNIEnv *env; - Mode mode = UPDATE_AND_RELEASE; - U jarray = nullptr; - T* narray = nullptr; - jboolean isCopy = false; - -public: - JNICriticalArray(JNIEnv *env) : env(env) {} - - JNICriticalArray(const JNICriticalArray &o) = delete; - JNICriticalArray(JNICriticalArray &&o) = delete; - JNICriticalArray& operator=(const JNICriticalArray &o) = delete; - JNICriticalArray& operator=(JNICriticalArray &&o) = delete; - - /** - * Release the acquired primitive array, RAII style. - */ - ~JNICriticalArray() { - release(); - } - - /** - * Manual release of the acquired primitive array, - * usually one likes to simply do this via the destructor, RAII style. - */ - void release() { - if( nullptr != narray ) { - env->ReleasePrimitiveArrayCritical(jarray, narray, mode); - this->jarray = nullptr; - this->narray = nullptr; - this->env = nullptr; - } - } - - /** - * Acquired the primitive array. - */ - T* get(U jarray, Mode mode=UPDATE_AND_RELEASE) { - if( nullptr == jarray ) { - return nullptr; - } - T* narray = static_cast<T*>( env->GetPrimitiveArrayCritical(jarray, &isCopy) ); - if( nullptr != narray ) { - this->mode = mode; - this->jarray = jarray; - this->narray = narray; - return narray; - } - return nullptr; - } - - /** - * Returns true if the primitive array had been acquired - * and the JVM utilizes a copy of the underlying java array. - */ - bool getIsCopy() const { return isCopy; } -}; - -#endif /* JNIMEM__HPP_ */ - diff --git a/java/jni/direct_bt/helper_dbt.cxx b/java/jni/direct_bt/helper_dbt.cxx index 5ce0489..23d5410 100644 --- a/java/jni/direct_bt/helper_dbt.cxx +++ b/java/jni/direct_bt/helper_dbt.cxx @@ -34,18 +34,13 @@ using namespace direct_bt; DirectBTJNISettings direct_bt::directBTJNISettings; -jclass direct_bt::search_class(JNIEnv *env, JavaUplink &object) -{ - return search_class(env, object.get_java_class().c_str()); -} - static std::string jStringEmpty(""); static std::string jAddressTypePublic("public"); static std::string jAddressTypeRandom("random"); BDAddressType direct_bt::fromJavaAdressTypeToBDAddressType(JNIEnv *env, jstring jAddressType) { if( nullptr != jAddressType ) { - std::string saddressType = from_jstring_to_string(env, jAddressType); + std::string saddressType = jau::from_jstring_to_string(env, jAddressType); if( jAddressTypePublic == saddressType ) { return BDAddressType::BDADDR_LE_PUBLIC; } @@ -58,23 +53,13 @@ BDAddressType direct_bt::fromJavaAdressTypeToBDAddressType(JNIEnv *env, jstring jstring direct_bt::fromBDAddressTypeToJavaAddressType(JNIEnv *env, BDAddressType bdAddressType) { switch( bdAddressType ) { case BDAddressType::BDADDR_LE_PUBLIC: - return from_string_to_jstring(env, jAddressTypePublic); + return jau::from_string_to_jstring(env, jAddressTypePublic); case BDAddressType::BDADDR_LE_RANDOM: - return from_string_to_jstring(env, jAddressTypeRandom); + return jau::from_string_to_jstring(env, jAddressTypeRandom); case BDAddressType::BDADDR_BREDR: // fall through intended default: - return from_string_to_jstring(env, jStringEmpty); - } -} - -JavaGlobalObj::~JavaGlobalObj() noexcept { - jobject obj = javaObjectRef.getObject(); - if( nullptr == obj || nullptr == mNotifyDeleted ) { - return; + return jau::from_string_to_jstring(env, jStringEmpty); } - JNIEnv *env = *jni_env; - env->CallVoidMethod(obj, mNotifyDeleted); - java_exception_check_and_throw(env, E_FILE_LINE); // would abort() if thrown } diff --git a/java/jni/direct_bt/helper_dbt.hpp b/java/jni/direct_bt/helper_dbt.hpp index 45d92d7..584e842 100644 --- a/java/jni/direct_bt/helper_dbt.hpp +++ b/java/jni/direct_bt/helper_dbt.hpp @@ -26,11 +26,8 @@ #ifndef HELPER_DBT_HPP_ #define HELPER_DBT_HPP_ -#include "JNIMem.hpp" #include "helper_base.hpp" -#include "direct_bt/JavaUplink.hpp" -#include "direct_bt/BasicTypes.hpp" #include "direct_bt/BTAddress.hpp" namespace direct_bt { @@ -52,134 +49,9 @@ namespace direct_bt { }; extern DirectBTJNISettings directBTJNISettings; - /** - * Implementation for JavaAnonObj, - * by simply wrapping a JNIGlobalRef instance. - */ - class JavaGlobalObj : public JavaAnonObj { - private: - JNIGlobalRef javaObjectRef; - jmethodID mNotifyDeleted; - - public: - static inline void check(const std::shared_ptr<JavaAnonObj> & shref, const char* file, int line) { - if( nullptr == shref ) { - throw direct_bt::RuntimeException("JavaGlobalObj::check: Null shared-JavaAnonObj", file, line); - } - const jobject obj = static_cast<const JavaGlobalObj*>(shref.get())->getObject(); - if( nullptr == obj ) { - throw direct_bt::RuntimeException("JavaGlobalObj::check: Null object", file, line); - } - } - static bool isValid(const std::shared_ptr<JavaAnonObj> & shref) noexcept { - if( nullptr == shref ) { - return false; - } - const jobject obj = static_cast<const JavaGlobalObj*>(shref.get())->getObject(); - if( nullptr == obj ) { - return false; - } - return true; - } - JavaGlobalObj(jobject obj, jmethodID mNotifyDeleted) noexcept - : javaObjectRef(obj), mNotifyDeleted(mNotifyDeleted) { } - - JavaGlobalObj(const JavaGlobalObj &o) noexcept = default; - JavaGlobalObj(JavaGlobalObj &&o) noexcept = default; - JavaGlobalObj& operator=(const JavaGlobalObj &o) noexcept = default; - JavaGlobalObj& operator=(JavaGlobalObj &&o) noexcept = default; - - virtual ~JavaGlobalObj() noexcept; - - std::string toString() const noexcept override { - const uint64_t ref = (uint64_t)(void*)javaObjectRef.getObject(); - return "JavaGlobalObj["+uint64HexString(ref, true)+"]"; - } - - /** Clears the java reference, i.e. nulling it, without deleting the global reference via JNI. */ - void clear() noexcept override { javaObjectRef.clear(); } - - JNIGlobalRef & getJavaObject() noexcept { return javaObjectRef; } - - /* Provides access to the stored GlobalRef as an jobject. */ - jobject getObject() const noexcept { return javaObjectRef.getObject(); } - /* Provides access to the stored GlobalRef as a jclass. */ - jclass getClass() const noexcept { return javaObjectRef.getClass(); } - - /* Provides access to the stored GlobalRef as an getJavaObject. */ - static JNIGlobalRef GetJavaObject(const std::shared_ptr<JavaAnonObj> & shref) noexcept { - return static_cast<JavaGlobalObj*>(shref.get())->getJavaObject(); - } - /* Provides access to the stored GlobalRef as an jobject. */ - static jobject GetObject(const std::shared_ptr<JavaAnonObj> & shref) noexcept { - return static_cast<JavaGlobalObj*>(shref.get())->getObject(); - } - - /* Provides access to the stored GlobalRef as a jclass. */ - static jclass GetClass(const std::shared_ptr<JavaAnonObj> & shref) noexcept { - return static_cast<JavaGlobalObj*>(shref.get())->getClass(); - } - }; - - jclass search_class(JNIEnv *env, JavaUplink &object); - - template <typename T> - jobject convert_vector_sharedptr_to_jarraylist(JNIEnv *env, std::vector<std::shared_ptr<T>>& array) - { - unsigned int array_size = array.size(); - - jmethodID arraylist_add; - jobject result = get_new_arraylist(env, array_size, &arraylist_add); - - if (0 == array_size) { - return result; - } - - for (unsigned int i = 0; i < array_size; ++i) { - std::shared_ptr<T> elem = array[i]; - std::shared_ptr<JavaAnonObj> objref = elem->getJavaObject(); - if ( nullptr == objref ) { - throw InternalError("JavaUplink element of array has no valid java-object: "+elem->toString(), E_FILE_LINE); - } - env->CallBooleanMethod(result, arraylist_add, JavaGlobalObj::GetObject(objref)); - } - return result; - } - BDAddressType fromJavaAdressTypeToBDAddressType(JNIEnv *env, jstring jAddressType); jstring fromBDAddressTypeToJavaAddressType(JNIEnv *env, BDAddressType bdAddressType); - template <typename T> - T *getDBTObject(JNIEnv *env, jobject obj) - { - jlong instance = env->GetLongField(obj, getInstanceField(env, obj)); - T *t = reinterpret_cast<T *>(instance); - if (t == nullptr) { - throw std::runtime_error("Trying to acquire null DBTObject"); - } - t->checkValid(); - return t; - } - - template <typename T> - T *getDBTObjectUnchecked(JNIEnv *env, jobject obj) - { - jlong instance = env->GetLongField(obj, getInstanceField(env, obj)); - return reinterpret_cast<T *>(instance); - } - - template <typename T> - void setDBTObject(JNIEnv *env, jobject obj, T *t) - { - if (t == nullptr) { - throw std::runtime_error("Trying to create null DBTObject"); - } - jlong instance = reinterpret_cast<jlong>(t); - env->SetLongField(obj, getInstanceField(env, obj), instance); - } - - - } // namespace direct_bt #endif /* HELPER_DBT_HPP_ */ diff --git a/java/jni/helper_base.cxx b/java/jni/helper_base.cxx index d30ba9f..ceac1c7 100644 --- a/java/jni/helper_base.cxx +++ b/java/jni/helper_base.cxx @@ -35,217 +35,23 @@ #define JAVA_MAIN_PACKAGE "org/tinyb" -jfieldID getField(JNIEnv *env, jobject obj, const char* field_name, const char* field_signature) { - jclass clazz = env->GetObjectClass(obj); - java_exception_check_and_throw(env, E_FILE_LINE); - // J == long - jfieldID res = env->GetFieldID(clazz, field_name, field_signature); - java_exception_check_and_throw(env, E_FILE_LINE); - return res; -} -jclass search_class(JNIEnv *env, const char *clazz_name) -{ - jclass clazz = env->FindClass(clazz_name); - java_exception_check_and_throw(env, E_FILE_LINE); - if (!clazz) - { - throw direct_bt::InternalError(std::string("no class found: ")+clazz_name, E_FILE_LINE); - } - return clazz; -} - -jclass search_class(JNIEnv *env, jobject obj) -{ - jclass clazz = env->GetObjectClass(obj); - java_exception_check_and_throw(env, E_FILE_LINE); - if (!clazz) - { - throw direct_bt::InternalError("no class found", E_FILE_LINE); - } - return clazz; -} - -jmethodID search_method(JNIEnv *env, jclass clazz, const char *method_name, - const char *prototype, bool is_static) -{ - jmethodID method; - if (is_static) - { - method = env->GetStaticMethodID(clazz, method_name, prototype); - } - else - { - method = env->GetMethodID(clazz, method_name, prototype); - } - java_exception_check_and_throw(env, E_FILE_LINE); - - if (!method) - { - throw direct_bt::InternalError(std::string("no method found: ")+method_name, E_FILE_LINE); - } - - return method; -} - -jfieldID search_field(JNIEnv *env, jclass clazz, const char *field_name, - const char *type, bool is_static) -{ - jfieldID field; - if (is_static) - { - field = env->GetStaticFieldID(clazz, field_name, type); - } - else - { - field = env->GetFieldID(clazz, field_name, type); - } - java_exception_check_and_throw(env, E_FILE_LINE); - - if (!field) - { - direct_bt::InternalError(std::string("no field found: ")+field_name, E_FILE_LINE); - } - - return field; -} - -bool from_jboolean_to_bool(jboolean val) -{ - bool result; - - if (val == JNI_TRUE) - { - result = true; - } - else - { - if (val == JNI_FALSE) - { - result = false; - } - else - { - throw direct_bt::InternalError("the jboolean value is not true/false", E_FILE_LINE); - } - } - - return result; -} - -std::string from_jstring_to_string(JNIEnv *env, jstring str) -{ - jboolean is_copy = JNI_TRUE; - if (!str) { - throw std::invalid_argument("String should not be null"); - } - const char *str_chars = (char *)env->GetStringUTFChars(str, &is_copy); - if (!str_chars) { - throw std::bad_alloc(); - } - const std::string string_to_write = std::string(str_chars); - - env->ReleaseStringUTFChars(str, str_chars); - - return string_to_write; -} - -jstring from_string_to_jstring(JNIEnv *env, const std::string & str) -{ - return env->NewStringUTF(str.c_str()); -} - jobject get_bluetooth_type(JNIEnv *env, const char *field_name) { - jclass b_type_enum = search_class(env, JAVA_MAIN_PACKAGE "/BluetoothType"); + jclass b_type_enum = jau::search_class(env, JAVA_MAIN_PACKAGE "/BluetoothType"); - jfieldID b_type_field = search_field(env, b_type_enum, field_name, "L" JAVA_MAIN_PACKAGE "/BluetoothType;", true); + jfieldID b_type_field = jau::search_field(env, b_type_enum, field_name, "L" JAVA_MAIN_PACKAGE "/BluetoothType;", true); jobject result = env->GetStaticObjectField(b_type_enum, b_type_field); env->DeleteLocalRef(b_type_enum); return result; } -jobject get_new_arraylist(JNIEnv *env, unsigned int size, jmethodID *add) -{ - jclass arraylist_class = search_class(env, "java/util/ArrayList"); - jmethodID arraylist_ctor = search_method(env, arraylist_class, "<init>", "(I)V", false); - - jobject result = env->NewObject(arraylist_class, arraylist_ctor, size); - if (!result) - { - throw direct_bt::InternalError("Cannot create instance of class ArrayList", E_FILE_LINE); - } - - *add = search_method(env, arraylist_class, "add", "(Ljava/lang/Object;)Z", false); - - env->DeleteLocalRef(arraylist_class); - return result; -} - -static void print_native_caught_exception_fwd2java(const std::exception &e, const char* file, int line) { - fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, e.what()); fflush(stderr); -} -static void print_native_caught_exception_fwd2java(const std::string &msg, const char* file, int line) { - fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, msg.c_str()); fflush(stderr); -} -static void print_native_caught_exception_fwd2java(const char * cmsg, const char* file, int line) { - fprintf(stderr, "Native exception caught @ %s:%d and forward to Java: %s\n", file, line, cmsg); fflush(stderr); -} - -void raise_java_exception(JNIEnv *env, const std::exception &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/Error"), e.what()); -} -void raise_java_exception(JNIEnv *env, const std::runtime_error &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::RuntimeException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::InternalError &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/InternalError"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::NullPointerException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/NullPointerException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::IllegalArgumentException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const std::invalid_argument &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::IllegalStateException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/IllegalStateException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::UnsupportedOperationException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/UnsupportedOperationException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::IndexOutOfBoundsException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/IndexOutOfBoundsException"), e.what()); -} -void raise_java_exception(JNIEnv *env, const std::bad_alloc &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), e.what()); -} -void raise_java_exception(JNIEnv *env, const direct_bt::OutOfMemoryError &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); - env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), e.what()); -} void raise_java_exception(JNIEnv *env, const direct_bt::BluetoothException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); + jau::print_native_caught_exception_fwd2java(e, file, line); env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what()); } void raise_java_exception(JNIEnv *env, const tinyb::BluetoothException &e, const char* file, int line) { - print_native_caught_exception_fwd2java(e, file, line); + jau::print_native_caught_exception_fwd2java(e, file, line); env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what()); } @@ -257,83 +63,41 @@ void rethrow_and_raise_java_exception_impl(JNIEnv *env, const char* file, int li // std::rethrow_exception(e); throw; // re-throw current exception } catch (const std::bad_alloc &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::OutOfMemoryError &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::InternalError &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::NullPointerException &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::IllegalArgumentException &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::IllegalStateException &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::UnsupportedOperationException &e) { - raise_java_exception(env, e, file, line); - } catch (const direct_bt::IndexOutOfBoundsException &e) { - raise_java_exception(env, e, file, line); + jau::raise_java_exception(env, e, file, line); + } catch (const jau::OutOfMemoryError &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::InternalError &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::NullPointerException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IllegalArgumentException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IllegalStateException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::UnsupportedOperationException &e) { + jau::raise_java_exception(env, e, file, line); + } catch (const jau::IndexOutOfBoundsException &e) { + jau::raise_java_exception(env, e, file, line); } catch (const direct_bt::BluetoothException &e) { raise_java_exception(env, e, file, line); } catch (const tinyb::BluetoothException &e) { raise_java_exception(env, e, file, line); - } catch (const direct_bt::RuntimeException &e) { - raise_java_exception(env, e, file, line); + } catch (const jau::RuntimeException &e) { + jau::raise_java_exception(env, e, file, line); } catch (const std::runtime_error &e) { - raise_java_exception(env, e, file, line); + jau::raise_java_exception(env, e, file, line); } catch (const std::invalid_argument &e) { - raise_java_exception(env, e, file, line); + jau::raise_java_exception(env, e, file, line); } catch (const std::exception &e) { - raise_java_exception(env, e, file, line); + jau::raise_java_exception(env, e, file, line); } catch (const std::string &msg) { - print_native_caught_exception_fwd2java(msg, file, line); + jau::print_native_caught_exception_fwd2java(msg, file, line); env->ThrowNew(env->FindClass("java/lang/Error"), msg.c_str()); } catch (const char *msg) { - print_native_caught_exception_fwd2java(msg, file, line); + jau::print_native_caught_exception_fwd2java(msg, file, line); env->ThrowNew(env->FindClass("java/lang/Error"), msg); } catch (...) { - print_native_caught_exception_fwd2java(_unknown_exception_type_msg, file, line); + jau::print_native_caught_exception_fwd2java(_unknown_exception_type_msg, file, line); env->ThrowNew(env->FindClass("java/lang/Error"), _unknown_exception_type_msg.c_str()); } } - -bool java_exception_check(JNIEnv *env, const char* file, int line) -{ - jthrowable e = env->ExceptionOccurred(); - if( nullptr != e ) { -#if 1 - // ExceptionDescribe prints an exception and a backtrace of the stack to a system error-reporting channel, such as stderr. - // The pending exception is cleared as a side-effect of calling this function. This is a convenience routine provided for debugging. - env->ExceptionDescribe(); -#endif - env->ExceptionClear(); // just be sure, to have same side-effects - - jclass eClazz = search_class(env, e); - jmethodID toString = search_method(env, eClazz, "toString", "()Ljava/lang/String;", false); - jstring jmsg = (jstring) env->CallObjectMethod(e, toString); - std::string msg = from_jstring_to_string(env, jmsg); - fprintf(stderr, "Java exception occurred @ %s:%d and forward to Java: %s\n", file, line, msg.c_str()); fflush(stderr); - - env->Throw(e); // re-throw the java exception - java side! - return true; - } - return false; -} - -void java_exception_check_and_throw(JNIEnv *env, const char* file, int line) -{ - jthrowable e = env->ExceptionOccurred(); - if( nullptr != e ) { - // ExceptionDescribe prints an exception and a backtrace of the stack to a system error-reporting channel, such as stderr. - // The pending exception is cleared as a side-effect of calling this function. This is a convenience routine provided for debugging. - env->ExceptionDescribe(); - env->ExceptionClear(); // just be sure, to have same side-effects - - jclass eClazz = search_class(env, e); - jmethodID toString = search_method(env, eClazz, "toString", "()Ljava/lang/String;", false); - jstring jmsg = (jstring) env->CallObjectMethod(e, toString); - std::string msg = from_jstring_to_string(env, jmsg); - fprintf(stderr, "Java exception occurred @ %s:%d and forward to Native: %s\n", file, line, msg.c_str()); fflush(stderr); - - throw direct_bt::RuntimeException("Java exception occurred @ %s : %d: "+msg, file, line); - } -} diff --git a/java/jni/helper_base.hpp b/java/jni/helper_base.hpp index fcc97c8..7af77e2 100644 --- a/java/jni/helper_base.hpp +++ b/java/jni/helper_base.hpp @@ -34,232 +34,13 @@ #include <functional> #include <jni.h> -#include "direct_bt/BasicTypes.hpp" -#include "tinyb/BluetoothException.hpp" +#include <jau/jni/helper_jni.hpp> -/** - * Return true if a java exception occurred, otherwise false. - * <p> - * In case of an exception, the information might be logged to stderr. - * </p> - * <p> - * In case of an exception, user shall release resourced in their JNI code - * and leave immediately. - * </p> - */ -bool java_exception_check(JNIEnv *env, const char* file, int line); - -/** - * Throws a C++ exception if a java exception occurred, otherwise do nothing. - * <p> - * In case of an exception, the information might be logged to stderr. - * </p> - * <p> - * In case of an exception and hence thrown C++ exception, - * might want to catch all and handle it via {@link #rethrow_and_raise_java_exception(JNIEnv*)}. - * </p> - */ -void java_exception_check_and_throw(JNIEnv *env, const char* file, int line); - - -jfieldID getField(JNIEnv *env, jobject obj, const char* field_name, const char* field_signature); -inline jfieldID getInstanceField(JNIEnv *env, jobject obj) { - return getField(env, obj, "nativeInstance", "J"); -} +#include "direct_bt/BTTypes.hpp" +#include "tinyb/BluetoothException.hpp" -jclass search_class(JNIEnv *env, const char *clazz_name); -jclass search_class(JNIEnv *env, jobject obj); -jmethodID search_method(JNIEnv *env, jclass clazz, const char *method_name, - const char *prototype, bool is_static); -jfieldID search_field(JNIEnv *env, jclass clazz, const char *field_name, - const char *type, bool is_static); -bool from_jboolean_to_bool(jboolean val); -std::string from_jstring_to_string(JNIEnv *env, jstring str); -jstring from_string_to_jstring(JNIEnv *env, const std::string & str); jobject get_bluetooth_type(JNIEnv *env, const char *field_name); -jobject get_new_arraylist(JNIEnv *env, unsigned int size, jmethodID *add); - -template <typename T> -T *castInstance(jlong instance) -{ - T *t = reinterpret_cast<T *>(instance); - if (t == nullptr) { - throw std::runtime_error("Trying to cast null object"); - } - return t; -} - -template <typename T> -T *getObjectRef(JNIEnv *env, jobject obj, const char* field_name) -{ - jlong jobj = env->GetLongField(obj, getField(env, obj, field_name, "J")); - java_exception_check_and_throw(env, E_FILE_LINE); - return reinterpret_cast<T *>(jobj); -} - -template <typename T> -void setObjectRef(JNIEnv *env, jobject obj, T *t, const char* field_name) -{ - jlong jobj = reinterpret_cast<jlong>(t); - env->SetLongField(obj, getField(env, obj, field_name, "J"), jobj); - java_exception_check_and_throw(env, E_FILE_LINE); -} - -template <typename T> -T *getInstance(JNIEnv *env, jobject obj) -{ - jlong instance = env->GetLongField(obj, getInstanceField(env, obj)); - T *t = reinterpret_cast<T *>(instance); - if (t == nullptr) { - throw std::runtime_error("Trying to acquire null object"); - } - return t; -} - -template <typename T> -T *getInstanceUnchecked(JNIEnv *env, jobject obj) -{ - jlong instance = env->GetLongField(obj, getInstanceField(env, obj)); - return reinterpret_cast<T *>(instance); -} - -template <typename T> -void setInstance(JNIEnv *env, jobject obj, T *t) -{ - if (t == nullptr) { - throw std::runtime_error("Trying to create null object"); - } - jlong instance = reinterpret_cast<jlong>(t); - env->SetLongField(obj, getInstanceField(env, obj), instance); -} - -inline void clearInstance(JNIEnv *env, jobject obj) { - env->SetLongField(obj, getInstanceField(env, obj), 0); -} - -template <typename T> -jobject generic_clone(JNIEnv *env, jobject obj) -{ - T *obj_generic = getInstance<T>(env, obj); - T *copy_generic = obj_generic->clone(); - - jclass generic_class = search_class(env, *copy_generic); - jmethodID generic_ctor = search_method(env, generic_class, "<init>", "(J)V", false); - - jobject result = env->NewObject(generic_class, generic_ctor, (jlong)copy_generic); - if (!result) - { - throw std::runtime_error("cannot create instance of class"); - } - - return result; -} - -template <typename T> -jobject convert_vector_uniqueptr_to_jarraylist(JNIEnv *env, std::vector<std::unique_ptr<T>>& array, - const char *ctor_prototype) -{ - unsigned int array_size = array.size(); - - jmethodID arraylist_add; - jobject result = get_new_arraylist(env, array_size, &arraylist_add); - - if (array_size == 0) - { - return result; - } - - jclass clazz = search_class(env, T::java_class().c_str()); - jmethodID clazz_ctor = search_method(env, clazz, "<init>", ctor_prototype, false); - - for (unsigned int i = 0; i < array_size; ++i) - { - T *elem = array[i].release(); - jobject object = env->NewObject(clazz, clazz_ctor, (jlong)elem); - if (!object) - { - throw direct_bt::InternalError("cannot create instance of class", E_FILE_LINE); - } - env->CallBooleanMethod(result, arraylist_add, object); - java_exception_check_and_throw(env, E_FILE_LINE); - } - return result; -} - -template <typename T> -jobject convert_vector_uniqueptr_to_jarraylist(JNIEnv *env, std::vector<std::unique_ptr<T>>& array, - const char *ctor_prototype, std::function<jobject(JNIEnv*, jclass, jmethodID, T*)> ctor) -{ - unsigned int array_size = array.size(); - - jmethodID arraylist_add; - jobject result = get_new_arraylist(env, array_size, &arraylist_add); - - if (array_size == 0) - { - return result; - } - - jclass clazz = search_class(env, T::java_class().c_str()); - jmethodID clazz_ctor = search_method(env, clazz, "<init>", ctor_prototype, false); - - for (unsigned int i = 0; i < array_size; ++i) - { - T *elem = array[i].release(); - jobject object = ctor(env, clazz, clazz_ctor, elem); - if (!object) - { - throw std::runtime_error("cannot create instance of class\n"); - } - env->CallBooleanMethod(result, arraylist_add, object); - java_exception_check_and_throw(env, E_FILE_LINE); - } - return result; -} - -template <typename T> -jobject convert_vector_sharedptr_to_jarraylist(JNIEnv *env, std::vector<std::shared_ptr<T>>& array, - const char *ctor_prototype, std::function<jobject(JNIEnv*, jclass, jmethodID, T*)> ctor) -{ - unsigned int array_size = array.size(); - - jmethodID arraylist_add; - jobject result = get_new_arraylist(env, array_size, &arraylist_add); - - if (array_size == 0) - { - return result; - } - - jclass clazz = search_class(env, T::java_class().c_str()); - jmethodID clazz_ctor = search_method(env, clazz, "<init>", ctor_prototype, false); - - for (unsigned int i = 0; i < array_size; ++i) - { - T *elem = array[i].get(); - jobject object = ctor(env, clazz, clazz_ctor, elem); - if (!object) - { - throw std::runtime_error("cannot create instance of class\n"); - } - env->CallBooleanMethod(result, arraylist_add, object); - java_exception_check_and_throw(env, E_FILE_LINE); - } - return result; -} -void raise_java_exception(JNIEnv *env, const std::exception &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const std::runtime_error &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::RuntimeException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::InternalError &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::NullPointerException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::IllegalArgumentException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const std::invalid_argument &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::IllegalStateException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::UnsupportedOperationException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::IndexOutOfBoundsException &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const std::bad_alloc &e, const char* file, int line); -void raise_java_exception(JNIEnv *env, const direct_bt::OutOfMemoryError &e, const char* file, int line); void raise_java_exception(JNIEnv *env, const direct_bt::BluetoothException &e, const char* file, int line); void raise_java_exception(JNIEnv *env, const tinyb::BluetoothException &e, const char* file, int line); diff --git a/java/jni/tinyb/helper_tinyb.cxx b/java/jni/tinyb/helper_tinyb.cxx index 68ee040..f170b6f 100644 --- a/java/jni/tinyb/helper_tinyb.cxx +++ b/java/jni/tinyb/helper_tinyb.cxx @@ -37,7 +37,7 @@ using namespace tinyb; jclass tinyb::search_class(JNIEnv *env, BluetoothObject &object) { - return search_class(env, object.get_java_class().c_str()); + return jau::search_class(env, object.get_java_class().c_str()); } BluetoothType tinyb::from_int_to_btype(int type) diff --git a/java/jni/tinyb/helper_tinyb.hpp b/java/jni/tinyb/helper_tinyb.hpp index d91051c..cdfad29 100644 --- a/java/jni/tinyb/helper_tinyb.hpp +++ b/java/jni/tinyb/helper_tinyb.hpp @@ -29,6 +29,7 @@ #pragma once #include "helper_base.hpp" + #include "tinyb/BluetoothObject.hpp" #include "tinyb/BluetoothException.hpp" |