summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-08-24 05:33:27 +0200
committerSven Gothel <[email protected]>2020-08-24 05:33:27 +0200
commitc1e543aacebd4c769abf4d6415c63d1a7ee6809d (patch)
tree7f7dc38fe61ca83406a2fda3956933e59cf32a64
parent790e705aa16f47effd1db6e58a84123b9e357c9f (diff)
BluetoothFactory/DBTEnv: Pass JVM properties to environment, access DEBUG, VERBOSE via lazy DBTEnv from C++ (
DEBUG := environment 'direct_bt_debug' or JVM property 'direct_bt.debug' VERBOSE := environment 'direct_bt_verbose' or JVM property 'direct_bt.verbose' This changes allows passing JVM properties as C++ environment variables, to be accessed via DBTEnv. JVM property names are renamed from 'foo.bar' to 'jvm_foo_bar' and can be queried via 'DBTEnv::getProperty("foo_bar")' as it will also attempt the 'jvm_' prefix if the plain name wasn't resolved. The singleton DBTEnv instance can be retrieved via DBTEnv::get(), which allows lazy initialization of DEBUG, VERBOSE from environment variables. This is required, as the JVM loads the native libraries first, initializes all native static variables and only then can pass the properties to the native environment via POSIX 'setenv(..)'. Hence users should never use static initialization from native code in such cases, otherwise they can't benefit from the unified JVM properties.
-rw-r--r--api/direct_bt/DBTEnv.hpp73
-rw-r--r--examples/java/ScannerTinyB10.java9
-rw-r--r--java/jni/BluetoothFactory.cxx24
-rw-r--r--java/org/tinyb/BluetoothFactory.java23
-rw-r--r--src/direct_bt/CMakeLists.txt2
-rw-r--r--src/direct_bt/DBTEnv.cpp49
-rw-r--r--src/tinyb/CMakeLists.txt2
7 files changed, 174 insertions, 8 deletions
diff --git a/api/direct_bt/DBTEnv.hpp b/api/direct_bt/DBTEnv.hpp
index b43c3390..c7a8c287 100644
--- a/api/direct_bt/DBTEnv.hpp
+++ b/api/direct_bt/DBTEnv.hpp
@@ -41,6 +41,9 @@ extern "C" {
namespace direct_bt {
class DBTEnv {
+ private:
+ DBTEnv();
+
public:
/**
* Module startup time t0 in monotonic time in milliseconds.
@@ -53,6 +56,76 @@ namespace direct_bt {
static uint64_t getElapsedMillisecond() {
return getCurrentMilliseconds() - startupTimeMilliseconds;
}
+
+ /**
+ * Returns the value of the environment's variable 'name'.
+ * <p>
+ * If there is no environment variable 'name',
+ * implementation will try the potentially Java JVM imported 'jvm_name'.
+ * </p>
+ * <p>
+ * Note that all Java JVM system properties are passed to the environment
+ * and all property names have replaced dots '.' to underscore '_'
+ * and 'jvm_' prepended.
+ * </p>
+ */
+ static const char * getProperty(const char *name);
+
+ /**
+ * Returns the value of the environment's variable 'name',
+ * or the 'default_value' if the environment variable's value is null.
+ * <p>
+ * Implementation uses getProperty(const char *name).
+ * </p>
+ */
+ static std::string getProperty(const char *name, const std::string & default_value);
+
+ /**
+ * Returns the boolean value of the environment's variable 'name',
+ * or the 'default_value' if the environment variable's value is null.
+ * <p>
+ * If the environment variable is set (value != null),
+ * true is determined if the value equals 'true'.
+ * </p>
+ * <p>
+ * Implementation uses getProperty(const char *name).
+ * </p>
+ */
+ static bool getBooleanProperty(const char *name, const bool default_value);
+
+ static DBTEnv& get() {
+ /**
+ * Thread safe starting with C++11 6.7:
+ *
+ * If control enters the declaration concurrently while the variable is being initialized,
+ * the concurrent execution shall wait for completion of the initialization.
+ *
+ * (Magic Statics)
+ *
+ * Avoiding non-working double checked locking.
+ */
+ static DBTEnv e;
+ return e;
+ }
+
+ /**
+ * Debug logging enabled or disabled.
+ * <p>
+ * Environment variable 'direct_bt_debug', boolean, default 'false'.
+ * </p>
+ */
+ const bool DEBUG;
+
+ /**
+ * Verbose info logging enabled or disabled.
+ * <p>
+ * Environment variable 'direct_bt_verbose', boolean, default 'false'.
+ * </p>
+ * <p>
+ * VERBOSE is also enabled if DEBUG is enabled!
+ * </p>
+ */
+ const bool VERBOSE;
};
} // namespace direct_bt
diff --git a/examples/java/ScannerTinyB10.java b/examples/java/ScannerTinyB10.java
index 1815bf50..9e49c079 100644
--- a/examples/java/ScannerTinyB10.java
+++ b/examples/java/ScannerTinyB10.java
@@ -488,6 +488,10 @@ public class ScannerTinyB10 {
System.setProperty("org.tinyb.debug", "true");
} else if( arg.equals("-verbose") ) {
System.setProperty("org.tinyb.verbose", "true");
+ } else if( arg.equals("-dbt_debug") ) {
+ System.setProperty("direct_bt.debug", "true"); // 'direct_bt_debug' from C++
+ } else if( arg.equals("-dbt_verbose") ) {
+ System.setProperty("direct_bt.verbose", "true"); // 'direct_bt_verbose' from C++
} else if( arg.equals("-default_dev_id") && args.length > (i+1) ) {
final int default_dev_id = Integer.valueOf(args[++i]).intValue();
if( 0 <= default_dev_id ) {
@@ -536,7 +540,10 @@ public class ScannerTinyB10 {
test.MULTI_MEASUREMENTS = -1;
}
}
- println("Run with '[-default_dev_id <adapter-index>] [-dev_id <adapter-index>] (-mac <device_address>)* [-disconnect] [-count <number>] [-single] (-wl <device_address>)* (-char <uuid>)* [-show_update_events] [-bluetoothManager <BluetoothManager-Implementation-Class-Name>] [-verbose] [-debug] [-shutdown <int>]'");
+ println("Run with '[-default_dev_id <adapter-index>] [-dev_id <adapter-index>] (-mac <device_address>)* "+
+ "[-disconnect] [-count <number>] [-single] (-wl <device_address>)* (-char <uuid>)* [-show_update_events] "+
+ "[-bluetoothManager <BluetoothManager-Implementation-Class-Name>] "+
+ "[-verbose] [-debug] [-dbt_verbose] [-dbt_debug] [-shutdown <int>]'");
}
println("BluetoothManager "+bluetoothManagerClazzName);
diff --git a/java/jni/BluetoothFactory.cxx b/java/jni/BluetoothFactory.cxx
index 42a2eca4..080fef28 100644
--- a/java/jni/BluetoothFactory.cxx
+++ b/java/jni/BluetoothFactory.cxx
@@ -49,3 +49,27 @@ jstring Java_org_tinyb_BluetoothFactory_getNativeAPIVersion(JNIEnv *env, jclass
return nullptr;
}
+void Java_org_tinyb_BluetoothFactory_setenv(JNIEnv *env, jclass clazz, jstring jname, jstring jvalue, jboolean overwrite)
+{
+ try {
+ (void) clazz;
+
+ std::string name = from_jstring_to_string(env, jname);
+ std::string value = from_jstring_to_string(env, jvalue);
+ if( name.length() > 0 ) {
+ if( value.length() > 0 ) {
+ setenv(name.c_str(), value.c_str(), overwrite);
+ } else {
+ setenv(name.c_str(), "true", overwrite);
+ }
+ }
+ } catch (std::bad_alloc &e) {
+ raise_java_exception(env, e);
+ } catch (std::runtime_error &e) {
+ raise_java_exception(env, e);
+ } catch (std::invalid_argument &e) {
+ raise_java_exception(env, e);
+ } catch (std::exception &e) {
+ raise_java_exception(env, e);
+ }
+}
diff --git a/java/org/tinyb/BluetoothFactory.java b/java/org/tinyb/BluetoothFactory.java
index a1ad9399..b5b822ea 100644
--- a/java/org/tinyb/BluetoothFactory.java
+++ b/java/org/tinyb/BluetoothFactory.java
@@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
+import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
@@ -210,6 +211,26 @@ public class BluetoothFactory {
}
try {
+ if( DEBUG ) {
+ System.err.println("BlootoothFactory: Mapping properties to native environment");
+ }
+ final Properties props = System.getProperties();
+ final Enumeration<?> enums = props.propertyNames();
+ while (enums.hasMoreElements()) {
+ final String key = (String) enums.nextElement();
+ final String value = props.getProperty(key);
+ final String key2 = "jvm_"+key.replace('.', '_');
+ if( DEBUG ) {
+ System.err.println(" <"+key+"> -> <"+key2+"> := <"+value+">");
+ }
+ setenv(key2, value, true /* overwrite */);
+ }
+ } catch (final Throwable e) {
+ System.err.println("Caught exception while forwarding system properties: "+e.getMessage());
+ e.printStackTrace();
+ }
+
+ try {
final Manifest manifest = getManifest(BluetoothFactory.class.getClassLoader(), new String[] { "org.tinyb" } );
final Attributes mfAttributes = null != manifest ? manifest.getMainAttributes() : null;
@@ -234,6 +255,7 @@ public class BluetoothFactory {
}
}
initializedID = id; // initialized!
+
t0 = BluetoothUtils.getCurrentMilliseconds();
APIVersion = JAPIVersion;
@@ -466,6 +488,7 @@ public class BluetoothFactory {
}
private native static String getNativeAPIVersion();
+ private native static void setenv(String name, String value, boolean overwrite);
/* pp */ static long getStartupTimeMilliseconds() { return t0; }
}
diff --git a/src/direct_bt/CMakeLists.txt b/src/direct_bt/CMakeLists.txt
index b28ada5f..be1b6dba 100644
--- a/src/direct_bt/CMakeLists.txt
+++ b/src/direct_bt/CMakeLists.txt
@@ -12,8 +12,8 @@ include_directories(
set (direct_bt_LIB_SRCS
${PROJECT_SOURCE_DIR}/src/direct_bt/dfa_utf8_decode.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/DBTEnv.cpp
- ${PROJECT_SOURCE_DIR}/src/ieee11073/DataTypes.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BasicTypes.cpp
+ ${PROJECT_SOURCE_DIR}/src/ieee11073/DataTypes.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/UUID.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/BTTypes.cpp
${PROJECT_SOURCE_DIR}/src/direct_bt/HCIComm.cpp
diff --git a/src/direct_bt/DBTEnv.cpp b/src/direct_bt/DBTEnv.cpp
index 7ea33e35..b76eeff5 100644
--- a/src/direct_bt/DBTEnv.cpp
+++ b/src/direct_bt/DBTEnv.cpp
@@ -30,13 +30,50 @@
#include <vector>
#include <cstdio>
-#include "DBTEnv.hpp"
+#include "direct_bt/DBTEnv.hpp"
+#include "direct_bt/dbt_debug.hpp"
-extern "C" {
- #include <inttypes.h>
- #include <unistd.h>
+using namespace direct_bt;
+
+const uint64_t DBTEnv::startupTimeMilliseconds = direct_bt::getCurrentMilliseconds();
+
+const char * DBTEnv::getProperty(const char *name) {
+ const char * value = getenv(name);
+ if( nullptr != value ) {
+ return value;
+ } else {
+ char name2[strlen(name)+4+1];
+ strcpy(name2, "jvm_");
+ strcpy(name2+4, name);
+ return getenv(name2);
+ }
}
-using namespace direct_bt;
+std::string DBTEnv::getProperty(const char *name, const std::string & default_value) {
+ const char * value = getProperty(name);
+ if( nullptr != value ) {
+ PLAIN_PRINT("DBTEnv::getProperty %s (default %s) -> %s", name, default_value.c_str(), value);
+ return value;
+ } else {
+ PLAIN_PRINT("DBTEnv::getProperty %s -> null -> %s (default)", name, default_value.c_str());
+ return default_value;
+ }
+}
+
+bool DBTEnv::getBooleanProperty(const char *name, const bool default_value) {
+ const char * value = getProperty(name);
+ if( nullptr != value ) {
+ bool res = 0==strcmp("true", value);
+ PLAIN_PRINT("DBTEnv::getBooleanProperty %s (default %d) -> %d/%s", name, default_value, res, value);
+ return res;
+ } else {
+ PLAIN_PRINT("DBTEnv::getBooleanProperty %s -> null -> %d (default)", name, default_value);
+ return default_value;
+ }
+}
-const uint64_t DBTEnv::startupTimeMilliseconds = getCurrentMilliseconds();
+DBTEnv::DBTEnv()
+: DEBUG( DBTEnv::getBooleanProperty("direct_bt_debug", false) ),
+ VERBOSE( DBTEnv::DEBUG || DBTEnv::getBooleanProperty("direct_bt_verbose", false) )
+{
+}
diff --git a/src/tinyb/CMakeLists.txt b/src/tinyb/CMakeLists.txt
index bff98e1b..cc32ce8d 100644
--- a/src/tinyb/CMakeLists.txt
+++ b/src/tinyb/CMakeLists.txt
@@ -14,6 +14,8 @@ include_directories(
set (tinyb_LIB_SRCS
${PROJECT_SOURCE_DIR}/src/direct_bt/dfa_utf8_decode.cpp
+ ${PROJECT_SOURCE_DIR}/src/direct_bt/DBTEnv.cpp
+ ${PROJECT_SOURCE_DIR}/src/direct_bt/BasicTypes.cpp
${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothObject.cpp
${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothEvent.cpp
${PROJECT_SOURCE_DIR}/src/tinyb/BluetoothManager.cpp