comparison Plugin/Plugin.cpp @ 7:b14ed1ea3a23

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 19 Oct 2023 11:14:45 +0200
parents c8f19e93ff99
children 26c08ff926a3
comparison
equal deleted inserted replaced
6:709e5347a390 7:b14ed1ea3a23
20 * You should have received a copy of the GNU General Public License 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/>. 21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 **/ 22 **/
23 23
24 24
25 #include "JavaLocalObject.h"
26 #include "JavaGlobalReference.h"
27 #include "OrthancBytes.h"
28 #include "OrthancString.h"
29 #include "JavaBytes.h"
30 #include "JavaString.h"
25 #include "JavaEnvironment.h" 31 #include "JavaEnvironment.h"
26 #include "JavaVirtualMachine.h" 32 #include "JavaVirtualMachine.h"
27 33
28 #include <orthanc/OrthancCPlugin.h> 34 #include <orthanc/OrthancCPlugin.h>
29 35
44 OrthancPluginContext* context_ = NULL; 50 OrthancPluginContext* context_ = NULL;
45 51
46 static std::unique_ptr<JavaVirtualMachine> java_; 52 static std::unique_ptr<JavaVirtualMachine> java_;
47 53
48 54
49
50 class JavaString : public NonCopyable
51 {
52 private:
53 JNIEnv* env_;
54 jstring javaStr_;
55 const char* cStr_;
56 jboolean isCopy_;
57
58 public:
59 JavaString(JNIEnv* env,
60 jstring javaStr) :
61 env_(env),
62 javaStr_(javaStr)
63 {
64 if (env == NULL ||
65 javaStr == NULL)
66 {
67 throw std::runtime_error("Null pointer");
68 }
69
70 cStr_ = env_->GetStringUTFChars(javaStr_, &isCopy_);
71 if (cStr_ == NULL)
72 {
73 throw std::runtime_error("Cannot read string");
74 }
75 }
76
77 ~JavaString()
78 {
79 /**
80 * "The ReleaseString-Chars call is necessary whether
81 * GetStringChars has set isCopy to JNI_TRUE or JNI_FALSE."
82 * https://stackoverflow.com/a/5863081
83 **/
84 env_->ReleaseStringUTFChars(javaStr_, cStr_);
85 }
86
87 const char* GetValue() const
88 {
89 return cStr_;
90 }
91 };
92
93
94 class JavaBytes : public NonCopyable
95 {
96 private:
97 JNIEnv* env_;
98 jbyteArray bytes_;
99 jbyte* data_;
100 jsize size_;
101 jboolean isCopy_;
102
103 public:
104 JavaBytes(JNIEnv* env,
105 jbyteArray bytes) :
106 env_(env),
107 bytes_(bytes)
108 {
109 if (env == NULL ||
110 bytes == NULL)
111 {
112 throw std::runtime_error("Null pointer");
113 }
114
115 size_ = env->GetArrayLength(bytes);
116
117 if (size_ == 0)
118 {
119 data_ = NULL;
120 }
121 else
122 {
123 data_ = env->GetByteArrayElements(bytes_, &isCopy_);
124 if (data_ == NULL)
125 {
126 throw std::runtime_error("Cannot read array of bytes");
127 }
128 }
129 }
130
131 ~JavaBytes()
132 {
133 if (size_ > 0)
134 {
135 env_->ReleaseByteArrayElements(bytes_, data_, 0);
136 }
137 }
138
139 const void* GetData() const
140 {
141 return data_;
142 }
143
144 size_t GetSize() const
145 {
146 return size_;
147 }
148 };
149
150
151 class OrthancString : public NonCopyable
152 {
153 private:
154 char* str_;
155
156 public:
157 OrthancString(char* str) :
158 str_(str)
159 {
160 }
161
162 ~OrthancString()
163 {
164 if (str_ != NULL)
165 {
166 OrthancPluginFreeString(context_, str_);
167 }
168 }
169
170 const char* GetValue() const
171 {
172 return str_;
173 }
174 };
175
176
177 class OrthancBytes : public NonCopyable
178 {
179 private:
180 OrthancPluginMemoryBuffer buffer_;
181
182 public:
183 OrthancBytes()
184 {
185 buffer_.data = NULL;
186 buffer_.size = 0;
187 }
188
189 ~OrthancBytes()
190 {
191 OrthancPluginFreeMemoryBuffer(context_, &buffer_);
192 }
193
194 OrthancPluginMemoryBuffer* GetMemoryBuffer()
195 {
196 return &buffer_;
197 }
198
199 const void* GetData() const
200 {
201 return buffer_.data;
202 }
203
204 size_t GetSize() const
205 {
206 return buffer_.size;
207 }
208 };
209
210
211 class JavaGlobalReference : public NonCopyable
212 {
213 private:
214 JavaVirtualMachine& jvm_;
215 jobject obj_;
216
217 public:
218 JavaGlobalReference(JavaVirtualMachine& jvm,
219 jobject obj) :
220 jvm_(jvm),
221 obj_(NULL)
222 {
223 if (obj == NULL)
224 {
225 throw std::runtime_error("Null pointer");
226 }
227
228 JavaEnvironment env(jvm);
229
230 obj_ = env.GetValue().NewGlobalRef(obj);
231 if (obj_ == NULL)
232 {
233 throw std::runtime_error("Cannot create global reference");
234 }
235 }
236
237 ~JavaGlobalReference()
238 {
239 assert(obj_ != NULL);
240
241 try
242 {
243 JavaEnvironment env(jvm_);
244 env.GetValue().DeleteGlobalRef(obj_);
245 }
246 catch (std::runtime_error& e)
247 {
248 OrthancPluginLogError(context_, e.what());
249 }
250 }
251
252 jobject GetValue()
253 {
254 assert(obj_ != NULL);
255 return obj_;
256 }
257 };
258
259
260 class LocalJavaObject : public NonCopyable
261 {
262 private:
263 JNIEnv* env_;
264 jobject obj_;
265
266 public:
267 LocalJavaObject(JavaEnvironment& env,
268 jobject obj,
269 bool objCanBeNull = false) :
270 env_(&env.GetValue()),
271 obj_(obj)
272 {
273 if (!objCanBeNull && obj == NULL)
274 {
275 throw std::runtime_error("Null pointer");
276 }
277 }
278
279 ~LocalJavaObject()
280 {
281 env_->DeleteLocalRef(obj_);
282 }
283
284 jobject GetValue()
285 {
286 return obj_;
287 }
288
289 static LocalJavaObject* CreateArrayOfStrings(JavaEnvironment& env,
290 const std::vector<std::string>& items)
291 {
292 LocalJavaObject emptyString(env, env.GetValue().NewStringUTF(""));
293
294 jobjectArray obj = env.GetValue().NewObjectArray(
295 items.size(), env.GetValue().FindClass("java/lang/String"),
296 emptyString.GetValue());
297
298 if (obj == NULL)
299 {
300 throw std::runtime_error("Cannot create an array of Java strings");
301 }
302 else
303 {
304 std::unique_ptr<LocalJavaObject> result(new LocalJavaObject(env, obj));
305
306 for (size_t i = 0; i < items.size(); i++)
307 {
308 LocalJavaObject item(env, env.GetValue().NewStringUTF(items[i].c_str()));
309 env.GetValue().SetObjectArrayElement(obj, i, item.GetValue());
310 }
311
312 return result.release();
313 }
314 }
315
316 static LocalJavaObject* CreateDictionary(JavaEnvironment& env,
317 const std::map<std::string, std::string>& items)
318 {
319 // NB: In JNI, there are no generics. All the templated arguments
320 // are taken as instances of the "Object" base class.
321
322 jclass cls = env.FindClass("java/util/HashMap");
323 jmethodID constructor = env.GetMethodID(cls, "<init>", "()V");
324 jmethodID setter = env.GetMethodID(cls, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
325 jobject obj = env.GetValue().NewObject(cls, constructor);
326
327 if (obj == NULL)
328 {
329 throw std::runtime_error("Cannot create a Java dictionary");
330 }
331 else
332 {
333 std::unique_ptr<LocalJavaObject> result(new LocalJavaObject(env, obj));
334
335 for (std::map<std::string, std::string>::const_iterator it = items.begin(); it != items.end(); ++it)
336 {
337 LocalJavaObject key(env, env.GetValue().NewStringUTF(it->first.c_str()));
338 LocalJavaObject value(env, env.GetValue().NewStringUTF(it->second.c_str()));
339 LocalJavaObject previousValue(env, env.GetValue().CallObjectMethod(obj, setter, key.GetValue(), value.GetValue()), true);
340 env.CheckException();
341 }
342
343 return result.release();
344 }
345 }
346 };
347
348
349
350 #include "NativeSDK.cpp" 55 #include "NativeSDK.cpp"
351 56
352 57
353 58
354 #define MAX_REST_CALLBACKS 10 59 #define MAX_REST_CALLBACKS 10
514 getParameters[request->getKeys[i]] = request->getValues[i]; 219 getParameters[request->getKeys[i]] = request->getValues[i];
515 } 220 }
516 221
517 JavaEnvironment env(*java_); 222 JavaEnvironment env(*java_);
518 223
519 LocalJavaObject joutput(env, env.ConstructJavaWrapper("be/uclouvain/orthanc/RestOutput", output)); 224 JavaLocalObject joutput(env, env.ConstructJavaWrapper("be/uclouvain/orthanc/RestOutput", output));
520 LocalJavaObject jmethod(env, env.ConstructEnumValue("be/uclouvain/orthanc/HttpMethod", request->method)); 225 JavaLocalObject jmethod(env, env.ConstructEnumValue("be/uclouvain/orthanc/HttpMethod", request->method));
521 LocalJavaObject juri(env, env.GetValue().NewStringUTF(uri == NULL ? "" : uri)); 226 JavaLocalObject juri(env, env.GetValue().NewStringUTF(uri == NULL ? "" : uri));
522 std::unique_ptr<LocalJavaObject> jgroups(LocalJavaObject::CreateArrayOfStrings(env, groups)); 227 std::unique_ptr<JavaLocalObject> jgroups(JavaLocalObject::CreateArrayOfStrings(env, groups));
523 std::unique_ptr<LocalJavaObject> jheaders(LocalJavaObject::CreateDictionary(env, headers)); 228 std::unique_ptr<JavaLocalObject> jheaders(JavaLocalObject::CreateDictionary(env, headers));
524 std::unique_ptr<LocalJavaObject> jgetParameters(LocalJavaObject::CreateDictionary(env, getParameters)); 229 std::unique_ptr<JavaLocalObject> jgetParameters(JavaLocalObject::CreateDictionary(env, getParameters));
525 LocalJavaObject jbody(env, env.ConstructByteArray(request->bodySize, request->body)); 230 JavaLocalObject jbody(env, env.ConstructByteArray(request->bodySize, request->body));
526 231
527 jmethodID call = env.GetMethodID( 232 jmethodID call = env.GetMethodID(
528 env.GetObjectClass(callback), "call", 233 env.GetObjectClass(callback), "call",
529 "(Lbe/uclouvain/orthanc/RestOutput;Lbe/uclouvain/orthanc/HttpMethod;Ljava/lang/String;" 234 "(Lbe/uclouvain/orthanc/RestOutput;Lbe/uclouvain/orthanc/HttpMethod;Ljava/lang/String;"
530 "[Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;[B)V"); 235 "[Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;[B)V");
587 292
588 if (!callbacks.empty()) 293 if (!callbacks.empty())
589 { 294 {
590 JavaEnvironment env(*java_); 295 JavaEnvironment env(*java_);
591 296
592 LocalJavaObject c(env, env.ConstructEnumValue("be/uclouvain/orthanc/ChangeType", changeType)); 297 JavaLocalObject c(env, env.ConstructEnumValue("be/uclouvain/orthanc/ChangeType", changeType));
593 LocalJavaObject r(env, env.ConstructEnumValue("be/uclouvain/orthanc/ResourceType", resourceType)); 298 JavaLocalObject r(env, env.ConstructEnumValue("be/uclouvain/orthanc/ResourceType", resourceType));
594 LocalJavaObject s(env, env.GetValue().NewStringUTF(resourceId == NULL ? "" : resourceId)); 299 JavaLocalObject s(env, env.GetValue().NewStringUTF(resourceId == NULL ? "" : resourceId));
595 300
596 for (std::list<jobject>::const_iterator 301 for (std::list<jobject>::const_iterator
597 callback = callbacks.begin(); callback != callbacks.end(); ++callback) 302 callback = callbacks.begin(); callback != callbacks.end(); ++callback)
598 { 303 {
599 assert(*callback != NULL); 304 assert(*callback != NULL);