jni: Extending native interface to NFD

- `startNfd` now accepts Map<String, String> instead of just a single
  String/homeDir parameter.
- new `getNfdLogModules` method returns all available log modules

Change-Id: I597579c69be06607de0734c034226fe9a359a2bc
Refs: #2746, #2623
diff --git a/app/src/main/jni/nfd-wrapper.cpp b/app/src/main/jni/nfd-wrapper.cpp
index d16049d..a5544a8 100644
--- a/app/src/main/jni/nfd-wrapper.cpp
+++ b/app/src/main/jni/nfd-wrapper.cpp
@@ -192,18 +192,61 @@
 
 static unique_ptr<Runner> g_runner;
 static boost::thread g_thread;
+static std::map<std::string, std::string> g_params;
 
 } // namespace nfd
 
+
+std::map<std::string, std::string>
+getParams(JNIEnv* env, jobject jParams)
+{
+  std::map<std::string, std::string> params;
+
+  jclass jcMap = env->GetObjectClass(jParams);
+  jclass jcSet = env->FindClass("java/util/Set");
+  jclass jcIterator = env->FindClass("java/util/Iterator");
+  jclass jcMapEntry = env->FindClass("java/util/Map$Entry");
+
+  jmethodID jcMapEntrySet      = env->GetMethodID(jcMap,      "entrySet", "()Ljava/util/Set;");
+  jmethodID jcSetIterator      = env->GetMethodID(jcSet,      "iterator", "()Ljava/util/Iterator;");
+  jmethodID jcIteratorHasNext  = env->GetMethodID(jcIterator, "hasNext",  "()Z");
+  jmethodID jcIteratorNext     = env->GetMethodID(jcIterator, "next",     "()Ljava/lang/Object;");
+  jmethodID jcMapEntryGetKey   = env->GetMethodID(jcMapEntry, "getKey",   "()Ljava/lang/Object;");
+  jmethodID jcMapEntryGetValue = env->GetMethodID(jcMapEntry, "getValue", "()Ljava/lang/Object;");
+
+  jobject jParamsEntrySet = env->CallObjectMethod(jParams, jcMapEntrySet);
+  jobject jParamsIterator = env->CallObjectMethod(jParamsEntrySet, jcSetIterator);
+  jboolean bHasNext = env->CallBooleanMethod(jParamsIterator, jcIteratorHasNext);
+  while (bHasNext) {
+    jobject entry = env->CallObjectMethod(jParamsIterator, jcIteratorNext);
+
+    jstring jKey = (jstring)env->CallObjectMethod(entry, jcMapEntryGetKey);
+    jstring jValue = (jstring)env->CallObjectMethod(entry, jcMapEntryGetValue);
+
+    const char* cKey = env->GetStringUTFChars(jKey, nullptr);
+    const char* cValue = env->GetStringUTFChars(jValue, nullptr);
+
+    params.insert(std::make_pair(cKey, cValue));
+
+    env->ReleaseStringUTFChars(jKey, cKey);
+    env->ReleaseStringUTFChars(jValue, cValue);
+
+    bHasNext = env->CallBooleanMethod(jParamsIterator, jcIteratorHasNext);
+  }
+
+  return params;
+}
+
+
 JNIEXPORT void JNICALL
-Java_net_named_1data_nfd_service_NfdService_startNfd(JNIEnv* env, jclass, jstring homePathJ)
+Java_net_named_1data_nfd_service_NfdService_startNfd(JNIEnv* env, jclass, jobject jParams)
 {
   if (nfd::g_runner.get() == nullptr) {
+    nfd::g_params = getParams(env, jParams);
+
     // set/update HOME environment variable
-    const char* homePath = env->GetStringUTFChars(homePathJ, nullptr);
-    ::setenv("HOME", homePath, true);
-    env->ReleaseStringUTFChars(homePathJ, homePath);
-    NFD_LOG_INFO("Use [" << homePath << "] as a security storage");
+    ::setenv("HOME", nfd::g_params["homePath"].c_str(), true);
+    NFD_LOG_INFO("Use [" << nfd::g_params["homePath"] << "] as a security storage");
 
     nfd::g_thread = boost::thread([] {
         NFD_LOG_INFO("Starting NFD...");
@@ -238,3 +281,20 @@
     // do not block anything
   }
 }
+
+JNIEXPORT jobject JNICALL
+Java_net_named_1data_nfd_service_NfdService_getNfdLogModules(JNIEnv* env, jclass)
+{
+  jclass jcLinkedList = env->FindClass("java/util/LinkedList");
+  jmethodID jcLinkedListConstructor = env->GetMethodID(jcLinkedList, "<init>", "()V");
+  jmethodID jcLinkedListAdd = env->GetMethodID(jcLinkedList, "add", "(Ljava/lang/Object;)Z");
+
+  jobject jModules = env->NewObject(jcLinkedList, jcLinkedListConstructor);
+
+  for (const auto& module : nfd::LoggerFactory::getInstance().getModules()) {
+    jstring jModule = env->NewStringUTF(module.c_str());
+    env->CallBooleanMethod(jModules, jcLinkedListAdd, jModule);
+  }
+
+  return jModules;
+}