arpadboda commented on a change in pull request #489: MINIFICPP-740: Add 
ability to run NiFi processors from Java and Python
URL: https://github.com/apache/nifi-minifi-cpp/pull/489#discussion_r259919624
 
 

 ##########
 File path: extensions/jni/jvm/JVMLoader.h
 ##########
 @@ -0,0 +1,514 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EXTENSIONS_JVMLOADER_H
+#define EXTENSIONS_JVMLOADER_H
+
+#include <string>
+#include <map>
+#include <vector>
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+#include "JavaClass.h"
+#include "JavaServicer.h"
+#include "../JavaException.h"
+#include "core/Core.h"
+#include <jni.h>
+#ifndef WIN32
+#include <dlfcn.h>
+#endif
+#include "Core.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace jni {
+
+/**
+ * Purpose and Justification: Provides a mapping function for jfields.
+ * Note that jFieldIDs aren't local references, so we don't need to worry
+ * about keeping them around. Thus this class provides us a caching mechanism.
+ */
+class FieldMapping {
+ public:
+  jfieldID getField(const std::string &clazz, const std::string &fnArg) {
+    std::lock_guard<std::mutex> guard(mutex_);
+    auto group = map_.find(clazz);
+    if (group != map_.end()) {
+      auto match = group->second.find(fnArg);
+      if (match != group->second.end()) {
+        return match->second;
+      }
+    }
+    return nullptr;
+  }
+
+  void putField(const std::string &clazz, const std::string &fnArg, jfieldID 
field) {
+    std::lock_guard<std::mutex> guard(mutex_);
+    map_[clazz].insert(std::make_pair(fnArg, field));
+  }
+
+ private:
+  std::mutex mutex_;
+  std::map<std::string, std::map<std::string, jfieldID>> map_;
+};
+
+typedef jint (*registerNatives_t)(JNIEnv* env, jclass clazz);
+
+jfieldID getPtrField(JNIEnv *env, jobject obj);
+
+template<typename T>
+T *getPtr(JNIEnv *env, jobject obj);
+
+template<typename T>
+void setPtr(JNIEnv *env, jobject obj, T *t);
+
+/**
+ * Purpose and Justification: Provides a singleton reference to a JVM.
+ *
+ * Since JVMs are singular in reference ( meaning that there cannot be more 
than one
+ * at any given time ), we need to create a singleton access pattern.
+ *
+ */
+class JVMLoader {
+ public:
+
+  bool initialized() {
+    return initialized_;
+  }
+
+  /**
+   * Attach the current thread
+   * @return JNIEnv reference.
+   */
+  JNIEnv *attach(const std::string &name = "") {
+    JNIEnv* jenv;
+    jint ret = jvm_->GetEnv((void**) &jenv, JNI_VERSION_1_8);
+    if (ret == JNI_EDETACHED) {
+      ret = jvm_->AttachCurrentThread((void**) &jenv, NULL);
+      if (ret != JNI_OK || jenv == NULL) {
+        throw std::runtime_error("Could not find class");
+      }
+    }
+
+    return jenv;
+  }
+
+  /**
+   * Returns a reference to an instantiated class loader
+   * @return class loader.
+   */
+  jobject getClassLoader() {
+    return gClassLoader;
+  }
+
+  /**
+   * Removes a class reference
+   * @param name class name
+   */
+  void remove_class(const std::string &name) {
+    std::lock_guard<std::mutex> lock(internal_mutex_);
+    auto finder = objects_.find(name);
+    if (finder != objects_.end()) {
+      auto oldClzz = finder->second;
+      JavaClass clazz(oldClzz);
+      attach(name)->DeleteGlobalRef(clazz.getReference());
+    }
+    objects_.erase(name);
+  }
+
+  /**
+   * Loads a class, creating a global reference to the jclass
+   * @param class name.
+   * @return JavaClass
+   */
+  JavaClass load_class(const std::string &clazz_name, JNIEnv *lenv = nullptr) {
+    // names should come with package/package/name, so we must normalize the 
name
+
+    JNIEnv *env = lenv;
+
+    std::string name = clazz_name;
+    name = utils::StringUtils::replaceAll(name, ".", "/");
+
+    if (env == nullptr) {
+      env = attach(name);
+    }
+
+    std::lock_guard<std::mutex> lock(internal_mutex_);
+    auto finder = objects_.find(name);
+    if (finder != objects_.end()) {
+      auto oldClzz = finder->second;
+      JavaClass clazz(oldClzz);
+      return clazz;
+    }
+
+    std::string modifiedName = name;
+    modifiedName = utils::StringUtils::replaceAll(modifiedName, "/", ".");
+
+    auto jstringclass = env->NewStringUTF(modifiedName.c_str());
+
+    auto preclass = env->CallObjectMethod(gClassLoader, gFindClassMethod, 
jstringclass);
+
+    minifi::jni::ThrowIf(env);
+
+    auto obj = (jclass) env->NewGlobalRef(preclass);
+
+    minifi::jni::ThrowIf(env);
+
+    auto clazzobj = static_cast<jclass>(obj);
+
+    JavaClass clazz(name, clazzobj, env);
+    objects_.insert(std::make_pair(name, clazz));
+    return clazz;
+  }
+
+  JavaClass getObjectClass(const std::string &name, jobject jobj) {
+    auto env = attach();
+    auto jcls = (jclass) env->NewGlobalRef(env->GetObjectClass(jobj));
+    return JavaClass(name, jcls, env);
+  }
+
+  static JVMLoader *getInstance() {
+    static JVMLoader jvm;
+    return &jvm;
+  }
+
+  JNIEnv *getEnv() {
+    return env_;
+  }
+
+  /**
+   * Returns an instance to the JVMLoader
+   * @param pathVector vector of paths
+   * @param otherOptions jvm options.
+   */
+  static JVMLoader *getInstance(const std::vector<std::string> &pathVector, 
const std::vector<std::string> &otherOptions = std::vector<std::string>()) {
+    JVMLoader *jvm = getInstance();
+    if (!jvm->initialized()) {
+      std::stringstream str;
+      std::vector<std::string> options;
+      for (const auto &path : pathVector) {
+        if (str.str().length() > 0) {
+#ifdef WIN32
 
 Review comment:
   ```
   #ifdef WIN32
   const char * delimiter = ";";
   #else 
   const char * delimiter = ":";
   #endif
   stringstream  str;
   std::copy(pathVector.begin(), pathVector.end(), 
std::ostream_iterator<std::string>(str, delimiter));
   ```
   
   A bit Pythonic, but I guess easier to read. 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to