Mercurial > hg > orthanc-java
annotate Plugin/Plugin.cpp @ 5:c8f19e93ff99
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 19 Oct 2023 08:49:07 +0200 |
parents | 9032ffb3a7d5 |
children | b14ed1ea3a23 |
rev | line source |
---|---|
0 | 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 | |
5 | 25 #include "JavaEnvironment.h" |
26 #include "JavaVirtualMachine.h" | |
27 | |
0 | 28 #include <orthanc/OrthancCPlugin.h> |
29 | |
30 #include <cassert> | |
31 #include <iostream> | |
32 #include <jni.h> | |
33 #include <list> | |
34 #include <map> | |
35 #include <memory> | |
36 #include <set> | |
37 #include <stdexcept> | |
38 #include <vector> | |
39 | |
40 #include <json/reader.h> | |
41 | |
42 #include "Mutex.h" | |
43 | |
5 | 44 OrthancPluginContext* context_ = NULL; |
0 | 45 |
46 static std::unique_ptr<JavaVirtualMachine> java_; | |
47 | |
48 | |
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" | |
351 | |
352 | |
353 | |
354 #define MAX_REST_CALLBACKS 10 | |
355 | |
356 class CallbacksConfiguration : public NonCopyable | |
357 { | |
358 private: | |
359 Mutex mutex_; | |
360 std::list<JavaGlobalReference*> onChangeCallbacks_; | |
361 std::vector<JavaGlobalReference*> onRestRequestCallbacks_; | |
362 | |
363 static void DestructCallbacks(std::list<JavaGlobalReference*>& lst) | |
364 { | |
365 for (std::list<JavaGlobalReference*>::iterator it = lst.begin(); it != lst.end(); ++it) | |
366 { | |
367 assert(*it != NULL); | |
368 delete *it; | |
369 } | |
370 } | |
371 | |
372 static void DestructCallbacks(std::vector<JavaGlobalReference*>& v) | |
373 { | |
374 for (size_t i = 0; i < v.size(); i++) | |
375 { | |
376 assert(v[i] != NULL); | |
377 delete v[i]; | |
378 } | |
379 } | |
380 | |
381 void CopyCallbacks(std::list<jobject>& target, | |
382 const std::list<JavaGlobalReference*>& lst) | |
383 { | |
384 Mutex::Locker locker(mutex_); | |
385 target.clear(); | |
386 | |
387 for (std::list<JavaGlobalReference*>::const_iterator it = lst.begin(); it != lst.end(); ++it) | |
388 { | |
389 assert(*it != NULL); | |
390 target.push_back((*it)->GetValue()); | |
391 } | |
392 } | |
393 | |
394 void AddCallback(std::list<JavaGlobalReference*>& lst, | |
395 JavaVirtualMachine& jvm, | |
396 jobject callback) | |
397 { | |
398 if (callback == NULL) | |
399 { | |
400 throw std::runtime_error("Null pointer"); | |
401 } | |
402 else | |
403 { | |
404 Mutex::Locker locker(mutex_); | |
405 lst.push_back(new JavaGlobalReference(jvm, callback)); | |
406 } | |
407 } | |
408 | |
409 public: | |
410 CallbacksConfiguration() | |
411 { | |
412 onRestRequestCallbacks_.reserve(MAX_REST_CALLBACKS); | |
413 } | |
414 | |
415 ~CallbacksConfiguration() | |
416 { | |
417 DestructCallbacks(onChangeCallbacks_); | |
418 DestructCallbacks(onRestRequestCallbacks_); | |
419 } | |
420 | |
421 void AddOnChangeCallback(JavaVirtualMachine& jvm, | |
422 jobject callback) | |
423 { | |
424 AddCallback(onChangeCallbacks_, jvm, callback); | |
425 } | |
426 | |
427 void GetOnChangeCallbacks(std::list<jobject>& target) | |
428 { | |
429 CopyCallbacks(target, onChangeCallbacks_); | |
430 } | |
431 | |
432 size_t AddOnRestRequestCallback(JavaVirtualMachine& jvm, | |
433 jobject callback) | |
434 { | |
435 if (callback == NULL) | |
436 { | |
437 throw std::runtime_error("Null pointer"); | |
438 } | |
439 else | |
440 { | |
441 Mutex::Locker locker(mutex_); | |
442 | |
443 if (onRestRequestCallbacks_.size() >= MAX_REST_CALLBACKS) | |
444 { | |
445 char buf[16]; | |
446 sprintf(buf, "%d", MAX_REST_CALLBACKS); | |
447 throw std::runtime_error("The Java plugin for Orthanc has been compiled for a maximum of " + | |
448 std::string(buf) + " REST callbacks"); | |
449 } | |
450 else | |
451 { | |
452 size_t result = onRestRequestCallbacks_.size(); | |
453 onRestRequestCallbacks_.push_back(new JavaGlobalReference(jvm, callback)); | |
454 return result; | |
455 } | |
456 } | |
457 } | |
458 | |
459 jobject GetOnRestCallback(size_t i) | |
460 { | |
461 Mutex::Locker locker(mutex_); | |
462 | |
463 if (i >= onRestRequestCallbacks_.size()) | |
464 { | |
465 throw std::runtime_error("Unknown REST callback"); | |
466 } | |
467 else | |
468 { | |
469 assert(onRestRequestCallbacks_[i] != NULL); | |
470 return onRestRequestCallbacks_[i]->GetValue(); | |
471 } | |
472 } | |
473 }; | |
474 | |
475 static std::unique_ptr<CallbacksConfiguration> callbacksConfiguration_; | |
476 | |
477 | |
478 | |
479 | |
480 template<size_t Index> | |
481 class RestCallbacksPool | |
482 { | |
483 private: | |
484 RestCallbacksPool<Index - 1> next_; | |
485 | |
486 static OrthancPluginErrorCode Callback(OrthancPluginRestOutput* output, | |
487 const char* uri, | |
488 const OrthancPluginHttpRequest* request) | |
489 { | |
490 try | |
491 { | |
492 jobject callback = callbacksConfiguration_->GetOnRestCallback(MAX_REST_CALLBACKS - Index); | |
493 if (callback == NULL) | |
494 { | |
495 throw std::runtime_error("Missing callback"); | |
496 } | |
497 | |
498 std::vector<std::string> groups; | |
499 groups.resize(request->groupsCount); | |
500 for (uint32_t i = 0; i < request->groupsCount; i++) | |
501 { | |
502 groups[i].assign(request->groups[i]); | |
503 } | |
504 | |
505 std::map<std::string, std::string> headers; | |
506 for (uint32_t i = 0; i < request->headersCount; i++) | |
507 { | |
508 headers[request->headersKeys[i]] = request->headersValues[i]; | |
509 } | |
510 | |
511 std::map<std::string, std::string> getParameters; | |
512 for (uint32_t i = 0; i < request->getCount; i++) | |
513 { | |
514 getParameters[request->getKeys[i]] = request->getValues[i]; | |
515 } | |
516 | |
517 JavaEnvironment env(*java_); | |
518 | |
519 LocalJavaObject joutput(env, env.ConstructJavaWrapper("be/uclouvain/orthanc/RestOutput", output)); | |
520 LocalJavaObject jmethod(env, env.ConstructEnumValue("be/uclouvain/orthanc/HttpMethod", request->method)); | |
521 LocalJavaObject juri(env, env.GetValue().NewStringUTF(uri == NULL ? "" : uri)); | |
522 std::unique_ptr<LocalJavaObject> jgroups(LocalJavaObject::CreateArrayOfStrings(env, groups)); | |
523 std::unique_ptr<LocalJavaObject> jheaders(LocalJavaObject::CreateDictionary(env, headers)); | |
524 std::unique_ptr<LocalJavaObject> jgetParameters(LocalJavaObject::CreateDictionary(env, getParameters)); | |
525 LocalJavaObject jbody(env, env.ConstructByteArray(request->bodySize, request->body)); | |
526 | |
527 jmethodID call = env.GetMethodID( | |
528 env.GetObjectClass(callback), "call", | |
529 "(Lbe/uclouvain/orthanc/RestOutput;Lbe/uclouvain/orthanc/HttpMethod;Ljava/lang/String;" | |
530 "[Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;[B)V"); | |
531 | |
532 env.GetValue().CallVoidMethod(callback, call, joutput.GetValue(), jmethod.GetValue(), juri.GetValue(), | |
533 jgroups->GetValue(), jheaders->GetValue(), jgetParameters->GetValue(), jbody.GetValue()); | |
534 env.CheckException(); | |
535 | |
536 return OrthancPluginErrorCode_Success; | |
537 } | |
538 catch (std::runtime_error& e) | |
539 { | |
540 OrthancPluginLogError(context_, e.what()); | |
541 return OrthancPluginErrorCode_Plugin; | |
542 } | |
543 catch (...) | |
544 { | |
545 OrthancPluginLogError(context_, "Caught native exception"); | |
546 return OrthancPluginErrorCode_Plugin; | |
547 } | |
548 } | |
549 | |
550 public: | |
551 OrthancPluginRestCallback GetCallback(size_t i) | |
552 { | |
553 if (i == 0) | |
554 { | |
555 return Callback; | |
556 } | |
557 else | |
558 { | |
559 return next_.GetCallback(i - 1); | |
560 } | |
561 } | |
562 }; | |
563 | |
564 template<> | |
565 class RestCallbacksPool<0> | |
566 { | |
567 public: | |
568 OrthancPluginRestCallback& GetCallback(size_t i) | |
569 { | |
570 throw std::runtime_error("Out of tuple"); | |
571 } | |
572 }; | |
573 | |
574 | |
575 static RestCallbacksPool<MAX_REST_CALLBACKS> restCallbacksPool_; | |
576 | |
577 | |
578 | |
579 OrthancPluginErrorCode OnChangeCallback(OrthancPluginChangeType changeType, | |
580 OrthancPluginResourceType resourceType, | |
581 const char* resourceId) | |
582 { | |
583 try | |
584 { | |
585 std::list<jobject> callbacks; | |
586 callbacksConfiguration_->GetOnChangeCallbacks(callbacks); | |
587 | |
588 if (!callbacks.empty()) | |
589 { | |
590 JavaEnvironment env(*java_); | |
591 | |
592 LocalJavaObject c(env, env.ConstructEnumValue("be/uclouvain/orthanc/ChangeType", changeType)); | |
593 LocalJavaObject r(env, env.ConstructEnumValue("be/uclouvain/orthanc/ResourceType", resourceType)); | |
594 LocalJavaObject s(env, env.GetValue().NewStringUTF(resourceId == NULL ? "" : resourceId)); | |
595 | |
596 for (std::list<jobject>::const_iterator | |
597 callback = callbacks.begin(); callback != callbacks.end(); ++callback) | |
598 { | |
599 assert(*callback != NULL); | |
600 | |
601 jmethodID call = env.GetMethodID( | |
602 env.GetObjectClass(*callback), "call", | |
603 "(Lbe/uclouvain/orthanc/ChangeType;Lbe/uclouvain/orthanc/ResourceType;Ljava/lang/String;)V"); | |
604 | |
605 env.GetValue().CallVoidMethod(*callback, call, c.GetValue(), r.GetValue(), s.GetValue()); | |
606 env.CheckException(); | |
607 } | |
608 } | |
609 | |
610 return OrthancPluginErrorCode_Success; | |
611 } | |
612 catch (std::runtime_error& e) | |
613 { | |
614 OrthancPluginLogError(context_, e.what()); | |
615 return OrthancPluginErrorCode_Plugin; | |
616 } | |
617 catch (...) | |
618 { | |
619 OrthancPluginLogError(context_, "Caught native exception"); | |
620 return OrthancPluginErrorCode_Plugin; | |
621 } | |
622 } | |
623 | |
624 | |
625 JNIEXPORT void RegisterOnChangeCallback(JNIEnv* env, jobject sdkObject, jobject callback) | |
626 { | |
627 try | |
628 { | |
629 callbacksConfiguration_->AddOnChangeCallback(*java_, callback); | |
630 } | |
631 catch (std::runtime_error& e) | |
632 { | |
5 | 633 JavaEnvironment::ThrowOrthancException(env, e.what()); |
0 | 634 } |
635 catch (...) | |
636 { | |
5 | 637 JavaEnvironment::ThrowOrthancException(env, OrthancPluginErrorCode_Plugin); |
0 | 638 } |
639 } | |
640 | |
641 | |
642 JNIEXPORT void RegisterOnRestRequestCallback(JNIEnv* env, jobject sdkObject, jstring regex, jobject callback) | |
643 { | |
644 try | |
645 { | |
646 JavaString cregex(env, regex); | |
647 size_t index = callbacksConfiguration_->AddOnRestRequestCallback(*java_, callback); | |
648 OrthancPluginRegisterRestCallbackNoLock(context_, cregex.GetValue(), restCallbacksPool_.GetCallback(index)); | |
649 } | |
650 catch (std::runtime_error& e) | |
651 { | |
5 | 652 JavaEnvironment::ThrowOrthancException(env, e.what()); |
0 | 653 } |
654 catch (...) | |
655 { | |
5 | 656 JavaEnvironment::ThrowOrthancException(env, OrthancPluginErrorCode_Plugin); |
0 | 657 } |
658 } | |
659 | |
660 | |
4
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
661 static void ParseJson(Json::Value& target, |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
662 const std::string& source) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
663 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
664 Json::CharReaderBuilder builder; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
665 builder.settings_["collectComments"] = false; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
666 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
667 const std::unique_ptr<Json::CharReader> reader(builder.newCharReader()); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
668 assert(reader.get() != NULL); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
669 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
670 JSONCPP_STRING err; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
671 if (!reader->parse(source.c_str(), source.c_str() + source.size(), &target, &err)) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
672 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
673 throw std::runtime_error("Cannot parse JSON: " + err); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
674 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
675 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
676 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
677 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
678 static bool HasOption(const Json::Value& json, |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
679 const std::string& key, |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
680 Json::ValueType type, |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
681 bool isMandatory) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
682 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
683 if (!json.isMember(key)) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
684 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
685 if (isMandatory) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
686 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
687 throw std::runtime_error("Missing configuration option for the Java plugin: \"" + key + "\""); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
688 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
689 else |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
690 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
691 return false; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
692 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
693 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
694 else if (json[key].type() == type) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
695 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
696 return true; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
697 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
698 else |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
699 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
700 throw std::runtime_error("The configuration option \"" + key + "\" for the Java plugin has not the proper type"); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
701 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
702 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
703 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
704 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
705 static std::string GetMandatoryString(const Json::Value& json, |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
706 const std::string& key) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
707 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
708 HasOption(json, key, Json::stringValue, true); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
709 assert(json.isMember(key) && |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
710 json[key].type() == Json::stringValue); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
711 return json[key].asString(); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
712 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
713 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
714 |
0 | 715 extern "C" |
716 { | |
717 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context) | |
718 { | |
719 context_ = context; | |
720 | |
721 /* Check the version of the Orthanc core */ | |
722 if (OrthancPluginCheckVersion(context) == 0) | |
723 { | |
724 char info[1024]; | |
725 sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin", | |
726 context->orthancVersion, | |
727 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, | |
728 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, | |
729 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); | |
730 OrthancPluginLogError(context, info); | |
731 return -1; | |
732 } | |
733 | |
4
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
734 OrthancPluginSetDescription(context, "Java plugin for Orthanc"); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
735 |
0 | 736 try |
737 { | |
738 { | |
739 // Sanity check to ensure that the compiler has created different callback functions | |
740 std::set<intptr_t> c; | |
741 for (unsigned int i = 0; i < MAX_REST_CALLBACKS; i++) | |
742 { | |
743 c.insert(reinterpret_cast<intptr_t>(restCallbacksPool_.GetCallback(i))); | |
744 } | |
745 | |
746 if (c.size() != MAX_REST_CALLBACKS) | |
747 { | |
748 throw std::runtime_error("The Java plugin has not been properly compiled"); | |
749 } | |
750 } | |
751 | |
4
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
752 Json::Value globalConfiguration; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
753 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
754 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
755 OrthancString tmp(OrthancPluginGetConfiguration(context)); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
756 ParseJson(globalConfiguration, tmp.GetValue()); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
757 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
758 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
759 static const std::string KEY_JAVA = "Java"; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
760 static const std::string KEY_ENABLED = "Enabled"; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
761 static const std::string KEY_CLASSPATH = "Classpath"; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
762 static const std::string KEY_INITIALIZATION_CLASS = "InitializationClass"; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
763 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
764 if (!HasOption(globalConfiguration, KEY_JAVA, Json::objectValue, false)) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
765 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
766 OrthancPluginLogInfo(context, "Java plugin is disabled"); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
767 return 0; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
768 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
769 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
770 Json::Value javaConfiguration = globalConfiguration[KEY_JAVA]; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
771 assert(javaConfiguration.isObject()); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
772 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
773 if (HasOption(javaConfiguration, KEY_ENABLED, Json::booleanValue, false) && |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
774 !javaConfiguration[KEY_ENABLED].asBool()) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
775 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
776 OrthancPluginLogInfo(context, "Java plugin is disabled"); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
777 return 0; |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
778 } |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
779 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
780 java_.reset(new JavaVirtualMachine(GetMandatoryString(javaConfiguration, KEY_CLASSPATH))); |
0 | 781 |
782 callbacksConfiguration_.reset(new CallbacksConfiguration); | |
783 OrthancPluginRegisterOnChangeCallback(context_, OnChangeCallback); | |
784 | |
785 JavaEnvironment env(*java_); | |
786 | |
787 { | |
788 std::vector<JNINativeMethod> methods; | |
789 JNI_LoadNatives(methods); | |
790 env.RegisterNatives("be/uclouvain/orthanc/NativeSDK", methods); | |
791 } | |
792 | |
793 { | |
794 std::vector<JNINativeMethod> methods; | |
795 methods.push_back((JNINativeMethod) { | |
796 const_cast<char*>("register"), | |
797 const_cast<char*>("(Lbe/uclouvain/orthanc/Callbacks$OnChange;)V"), | |
798 (void*) RegisterOnChangeCallback }); | |
799 methods.push_back((JNINativeMethod) { | |
800 const_cast<char*>("register"), | |
801 const_cast<char*>("(Ljava/lang/String;Lbe/uclouvain/orthanc/Callbacks$OnRestRequest;)V"), | |
802 (void*) RegisterOnRestRequestCallback }); | |
803 env.RegisterNatives("be/uclouvain/orthanc/Callbacks", methods); | |
804 } | |
4
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
805 |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
806 if (HasOption(javaConfiguration, KEY_INITIALIZATION_CLASS, Json::stringValue, false)) |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
807 { |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
808 env.FindClass(javaConfiguration[KEY_INITIALIZATION_CLASS].asString()); |
9032ffb3a7d5
added configuration options
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
809 } |
0 | 810 } |
811 catch (std::runtime_error& e) | |
812 { | |
813 OrthancPluginLogError(context, e.what()); | |
814 return -1; | |
815 } | |
816 | |
817 return 0; | |
818 } | |
819 | |
820 | |
821 ORTHANC_PLUGINS_API void OrthancPluginFinalize() | |
822 { | |
823 if (java_.get() != NULL) | |
824 { | |
825 callbacksConfiguration_.reset(NULL); | |
826 | |
827 try | |
828 { | |
829 JavaEnvironment env(*java_); | |
830 env.RunGarbageCollector(); | |
831 } | |
832 catch (std::runtime_error& e) | |
833 { | |
834 OrthancPluginLogError(context_, e.what()); | |
835 } | |
836 | |
837 java_.reset(NULL); | |
838 } | |
839 } | |
840 | |
841 | |
842 ORTHANC_PLUGINS_API const char* OrthancPluginGetName() | |
843 { | |
844 return "java"; | |
845 } | |
846 | |
847 | |
848 ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() | |
849 { | |
850 return PLUGIN_VERSION; | |
851 } | |
852 } |