comparison 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
comparison
equal deleted inserted replaced
4:9032ffb3a7d5 5:c8f19e93ff99
1 /**
2 * SPDX-FileCopyrightText: 2023 Sebastien Jodogne, UCLouvain, Belgium
3 * SPDX-License-Identifier: GPL-3.0-or-later
4 */
5
6 /**
7 * Java plugin for Orthanc
8 * Copyright (C) 2023 Sebastien Jodogne, UCLouvain, Belgium
9 *
10 * This program is free software: you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 **/
23
24
25 #include "JavaEnvironment.h"
26
27 #include <cassert>
28 #include <stdexcept>
29
30 extern OrthancPluginContext* context_;
31
32
33 static const char* ORTHANC_EXCEPTION_JAVA_CLASS = "be/uclouvain/orthanc/OrthancException";
34
35
36 JavaEnvironment::JavaEnvironment(JNIEnv* env) :
37 jvm_(NULL),
38 env_(env)
39 {
40 if (env_ == NULL)
41 {
42 throw std::runtime_error("Null pointer");
43 }
44 }
45
46
47 JavaEnvironment::JavaEnvironment(JavaVirtualMachine& jvm) :
48 jvm_(&jvm.GetValue())
49 {
50 jint status = jvm_->GetEnv((void **) &env_, JNI_VERSION_1_6);
51
52 switch (status)
53 {
54 case JNI_OK:
55 break;
56
57 case JNI_EDETACHED:
58 {
59 jint code = jvm_->AttachCurrentThread((void **) &env_, NULL);
60 if (code != JNI_OK)
61 {
62 throw std::runtime_error("Cannot attach thread");
63 }
64 break;
65 }
66
67 case JNI_EVERSION:
68 throw std::runtime_error("JNI version not supported");
69
70 default:
71 throw std::runtime_error("Not implemented");
72 }
73
74 if (env_ == NULL)
75 {
76 throw std::runtime_error("Error inside JNI");
77 }
78 }
79
80
81 JavaEnvironment::~JavaEnvironment()
82 {
83 if (jvm_ != NULL)
84 {
85 jvm_->DetachCurrentThread();
86 }
87 }
88
89
90 JNIEnv& JavaEnvironment::GetValue()
91 {
92 assert(env_ != NULL);
93 return *env_;
94 }
95
96
97 void JavaEnvironment::CheckException()
98 {
99 if (env_->ExceptionCheck() == JNI_TRUE)
100 {
101 env_->ExceptionClear();
102 throw std::runtime_error("An exception has occurred in Java");
103 }
104 }
105
106
107 void JavaEnvironment::ThrowException(const std::string& fqn,
108 const std::string& message)
109 {
110 if (GetValue().ThrowNew(FindClass(fqn), message.c_str()) != 0)
111 {
112 std::string message = "Cannot throw exception " + fqn;
113 OrthancPluginLogError(context_, message.c_str());
114 }
115 }
116
117
118 void JavaEnvironment::ThrowOrthancException(const std::string& message)
119 {
120 ThrowException(ORTHANC_EXCEPTION_JAVA_CLASS, message);
121 }
122
123
124 void JavaEnvironment::ThrowOrthancException(OrthancPluginErrorCode code)
125 {
126 ThrowException(ORTHANC_EXCEPTION_JAVA_CLASS, OrthancPluginGetErrorDescription(context_, code));
127 }
128
129
130 void JavaEnvironment::ThrowOrthancException(JNIEnv* env,
131 const std::string& message)
132 {
133 JavaEnvironment e(env);
134 e.ThrowOrthancException(message);
135 }
136
137
138 void JavaEnvironment::ThrowOrthancException(JNIEnv* env,
139 OrthancPluginErrorCode code)
140 {
141 JavaEnvironment e(env);
142 e.ThrowOrthancException(code);
143 }
144
145
146 void JavaEnvironment::RegisterNatives(const std::string& fqn,
147 const std::vector<JNINativeMethod>& methods)
148 {
149 if (!methods.empty())
150 {
151 if (env_->RegisterNatives(FindClass(fqn), &methods[0], methods.size()) < 0)
152 {
153 throw std::runtime_error("Unable to register the native methods");
154 }
155 }
156 }
157
158
159 void JavaEnvironment::RunGarbageCollector()
160 {
161 assert(env_ != NULL);
162
163 jclass system = FindClass("java/lang/System");
164
165 jmethodID runFinalization = env_->GetStaticMethodID(system, "gc", "()V");
166 if (runFinalization != NULL)
167 {
168 env_->CallStaticVoidMethod(system, runFinalization);
169 CheckException();
170 }
171 else
172 {
173 throw std::runtime_error("Cannot run garbage collector");
174 }
175 }
176
177
178 jclass JavaEnvironment::FindClass(const std::string& fqn)
179 {
180 jclass c = GetValue().FindClass(fqn.c_str());
181
182 if (c == NULL)
183 {
184 throw std::runtime_error("Unable to find class: " + fqn);
185 }
186 else
187 {
188 return c;
189 }
190 }
191
192
193 jclass JavaEnvironment::GetObjectClass(jobject obj)
194 {
195 jclass c = GetValue().GetObjectClass(obj);
196
197 if (c == NULL)
198 {
199 throw std::runtime_error("Unable to get class of object");
200 }
201 else
202 {
203 return c;
204 }
205 }
206
207
208 jmethodID JavaEnvironment::GetMethodID(jclass c,
209 const std::string& method,
210 const std::string& signature)
211 {
212 jmethodID m = GetValue().GetMethodID(c, method.c_str(), signature.c_str());
213
214 if (m == NULL)
215 {
216 throw std::runtime_error("Unable to locate method in class");
217 }
218 else
219 {
220 return m;
221 }
222 }
223
224
225 jobject JavaEnvironment::ConstructJavaWrapper(const std::string& fqn,
226 void* nativeObject)
227 {
228 jclass cls = FindClass(fqn);
229 jmethodID constructor = GetMethodID(cls, "<init>", "(J)V");
230 jobject obj = env_->NewObject(cls, constructor, reinterpret_cast<intptr_t>(nativeObject));
231
232 if (obj == NULL)
233 {
234 throw std::runtime_error("Cannot create Java wrapper around C/C++ object: " + fqn);
235 }
236 else
237 {
238 return obj;
239 }
240 }
241
242
243 jbyteArray JavaEnvironment::ConstructByteArray(const size_t size,
244 const void* data)
245 {
246 assert(env_ != NULL);
247 jbyteArray obj = env_->NewByteArray(size);
248 if (obj == NULL)
249 {
250 throw std::runtime_error("Cannot create a byte array");
251 }
252 else
253 {
254 if (size > 0)
255 {
256 env_->SetByteArrayRegion(obj, 0, size, reinterpret_cast<const jbyte*>(data));
257 }
258
259 return obj;
260 }
261 }
262
263
264 jobject JavaEnvironment::ConstructEnumValue(const std::string& fqn,
265 int value)
266 {
267 assert(env_ != NULL);
268 jclass cls = FindClass(fqn);
269
270 std::string signature = "(I)L" + fqn + ";";
271 jmethodID constructor = env_->GetStaticMethodID(cls, "getInstance", signature.c_str());
272 if (constructor != NULL)
273 {
274 jobject obj = env_->CallStaticObjectMethod(cls, constructor, static_cast<jint>(value));
275 CheckException();
276 return obj;
277 }
278 else
279 {
280 char buf[16];
281 sprintf(buf, "%d", value);
282 throw std::runtime_error("Cannot create enumeration value: " + fqn + " " + buf);
283 }
284 }