diff Plugin/JavaEnvironment.cpp @ 5:c8f19e93ff99

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 19 Oct 2023 08:49:07 +0200
parents
children 1c407ba1d311
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugin/JavaEnvironment.cpp	Thu Oct 19 08:49:07 2023 +0200
@@ -0,0 +1,284 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Sebastien Jodogne, UCLouvain, Belgium
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/**
+ * Java plugin for Orthanc
+ * Copyright (C) 2023 Sebastien Jodogne, UCLouvain, Belgium
+ *
+ * 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/>.
+ **/
+
+
+#include "JavaEnvironment.h"
+
+#include <cassert>
+#include <stdexcept>
+
+extern OrthancPluginContext* context_;
+
+
+static const char* ORTHANC_EXCEPTION_JAVA_CLASS = "be/uclouvain/orthanc/OrthancException";
+
+
+JavaEnvironment::JavaEnvironment(JNIEnv* env) :
+  jvm_(NULL),
+  env_(env)
+{
+  if (env_ == NULL)
+  {
+    throw std::runtime_error("Null pointer");
+  }
+}
+
+
+JavaEnvironment::JavaEnvironment(JavaVirtualMachine& jvm) :
+  jvm_(&jvm.GetValue())
+{
+  jint status = jvm_->GetEnv((void **) &env_, JNI_VERSION_1_6);
+
+  switch (status)
+  {
+    case JNI_OK:
+      break;
+
+    case JNI_EDETACHED:
+    {
+      jint code = jvm_->AttachCurrentThread((void **) &env_, NULL);
+      if (code != JNI_OK)
+      {
+        throw std::runtime_error("Cannot attach thread");
+      }
+      break;
+    }
+
+    case JNI_EVERSION:
+      throw std::runtime_error("JNI version not supported");
+
+    default:
+      throw std::runtime_error("Not implemented");
+  }
+
+  if (env_ == NULL)
+  {
+    throw std::runtime_error("Error inside JNI");
+  }
+}
+
+
+JavaEnvironment::~JavaEnvironment()
+{
+  if (jvm_ != NULL)
+  {
+    jvm_->DetachCurrentThread();
+  }
+}
+
+
+JNIEnv& JavaEnvironment::GetValue()
+{
+  assert(env_ != NULL);
+  return *env_;
+}
+
+
+void JavaEnvironment::CheckException()
+{
+  if (env_->ExceptionCheck() == JNI_TRUE)
+  {
+    env_->ExceptionClear();
+    throw std::runtime_error("An exception has occurred in Java");
+  }
+}
+
+
+void JavaEnvironment::ThrowException(const std::string& fqn,
+                                     const std::string& message)
+{
+  if (GetValue().ThrowNew(FindClass(fqn), message.c_str()) != 0)
+  {
+    std::string message = "Cannot throw exception " + fqn;
+    OrthancPluginLogError(context_, message.c_str());
+  }
+}
+
+
+void JavaEnvironment::ThrowOrthancException(const std::string& message)
+{
+  ThrowException(ORTHANC_EXCEPTION_JAVA_CLASS, message);
+}
+
+
+void JavaEnvironment::ThrowOrthancException(OrthancPluginErrorCode code)
+{
+  ThrowException(ORTHANC_EXCEPTION_JAVA_CLASS, OrthancPluginGetErrorDescription(context_, code));
+}
+
+
+void JavaEnvironment::ThrowOrthancException(JNIEnv* env,
+                                            const std::string& message)
+{
+  JavaEnvironment e(env);
+  e.ThrowOrthancException(message);
+}
+
+
+void JavaEnvironment::ThrowOrthancException(JNIEnv* env,
+                                            OrthancPluginErrorCode code)
+{
+  JavaEnvironment e(env);
+  e.ThrowOrthancException(code);
+}
+
+
+void JavaEnvironment::RegisterNatives(const std::string& fqn,
+                                      const std::vector<JNINativeMethod>& methods)
+{
+  if (!methods.empty())
+  {
+    if (env_->RegisterNatives(FindClass(fqn), &methods[0], methods.size()) < 0)
+    {
+      throw std::runtime_error("Unable to register the native methods");
+    }
+  }
+}
+
+
+void JavaEnvironment::RunGarbageCollector()
+{
+  assert(env_ != NULL);
+
+  jclass system = FindClass("java/lang/System");
+
+  jmethodID runFinalization = env_->GetStaticMethodID(system, "gc", "()V");
+  if (runFinalization != NULL)
+  {
+    env_->CallStaticVoidMethod(system, runFinalization);
+    CheckException();
+  }
+  else
+  {
+    throw std::runtime_error("Cannot run garbage collector");
+  }
+}
+
+
+jclass JavaEnvironment::FindClass(const std::string& fqn)
+{
+  jclass c = GetValue().FindClass(fqn.c_str());
+
+  if (c == NULL)
+  {
+    throw std::runtime_error("Unable to find class: " + fqn);
+  }
+  else
+  {
+    return c;
+  }
+}
+
+
+jclass JavaEnvironment::GetObjectClass(jobject obj)
+{
+  jclass c = GetValue().GetObjectClass(obj);
+
+  if (c == NULL)
+  {
+    throw std::runtime_error("Unable to get class of object");
+  }
+  else
+  {
+    return c;
+  }
+}
+
+
+jmethodID JavaEnvironment::GetMethodID(jclass c,
+                                       const std::string& method,
+                                       const std::string& signature)
+{
+  jmethodID m = GetValue().GetMethodID(c, method.c_str(), signature.c_str());
+
+  if (m == NULL)
+  {
+    throw std::runtime_error("Unable to locate method in class");
+  }
+  else
+  {
+    return m;
+  }
+}
+
+
+jobject JavaEnvironment::ConstructJavaWrapper(const std::string& fqn,
+                                              void* nativeObject)
+{
+  jclass cls = FindClass(fqn);
+  jmethodID constructor = GetMethodID(cls, "<init>", "(J)V");
+  jobject obj = env_->NewObject(cls, constructor, reinterpret_cast<intptr_t>(nativeObject));
+
+  if (obj == NULL)
+  {
+    throw std::runtime_error("Cannot create Java wrapper around C/C++ object: " + fqn);
+  }
+  else
+  {
+    return obj;
+  }
+}
+
+
+jbyteArray JavaEnvironment::ConstructByteArray(const size_t size,
+                                               const void* data)
+{
+  assert(env_ != NULL);
+  jbyteArray obj = env_->NewByteArray(size);
+  if (obj == NULL)
+  {
+    throw std::runtime_error("Cannot create a byte array");
+  }
+  else
+  {
+    if (size > 0)
+    {
+      env_->SetByteArrayRegion(obj, 0, size, reinterpret_cast<const jbyte*>(data));
+    }
+
+    return obj;
+  }
+}
+
+
+jobject JavaEnvironment::ConstructEnumValue(const std::string& fqn,
+                                            int value)
+{
+  assert(env_ != NULL);
+  jclass cls = FindClass(fqn);
+
+  std::string signature = "(I)L" + fqn + ";";
+  jmethodID constructor = env_->GetStaticMethodID(cls, "getInstance", signature.c_str());
+  if (constructor != NULL)
+  {
+    jobject obj = env_->CallStaticObjectMethod(cls, constructor, static_cast<jint>(value));
+    CheckException();
+    return obj;
+  }
+  else
+  {
+    char buf[16];
+    sprintf(buf, "%d", value);
+    throw std::runtime_error("Cannot create enumeration value: " + fqn + " " + buf);
+  }
+}