|
1 /* |
|
2 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
3 * you may not use this file except in compliance with the License. |
|
4 * You may obtain a copy of the License at |
|
5 * |
|
6 * http://www.apache.org/licenses/LICENSE-2.0 |
|
7 * |
|
8 * Unless required by applicable law or agreed to in writing, software |
|
9 * distributed under the License is distributed on an "AS IS" BASIS, |
|
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
11 * See the License for the specific language governing permissions and |
|
12 * limitations under the License. |
|
13 */ |
|
14 |
|
15 #include <map> |
|
16 #include <string.h> |
|
17 #include <jni.h> |
|
18 |
|
19 #include "JCCEnv.h" |
|
20 |
|
21 |
|
22 #if defined(_MSC_VER) || defined(__WIN32) |
|
23 _DLL_EXPORT DWORD VM_ENV = 0; |
|
24 #else |
|
25 pthread_key_t JCCEnv::VM_ENV = (pthread_key_t) NULL; |
|
26 #endif |
|
27 |
|
28 #if defined(_MSC_VER) || defined(__WIN32) |
|
29 |
|
30 static CRITICAL_SECTION *mutex = NULL; |
|
31 |
|
32 class lock { |
|
33 public: |
|
34 lock() { |
|
35 EnterCriticalSection(mutex); |
|
36 } |
|
37 virtual ~lock() { |
|
38 LeaveCriticalSection(mutex); |
|
39 } |
|
40 }; |
|
41 |
|
42 #else |
|
43 |
|
44 static pthread_mutex_t *mutex = NULL; |
|
45 |
|
46 class lock { |
|
47 public: |
|
48 lock() { |
|
49 pthread_mutex_lock(mutex); |
|
50 } |
|
51 virtual ~lock() { |
|
52 pthread_mutex_unlock(mutex); |
|
53 } |
|
54 }; |
|
55 |
|
56 #endif |
|
57 |
|
58 JCCEnv::JCCEnv(JavaVM *vm, JNIEnv *vm_env) |
|
59 { |
|
60 #if defined(_MSC_VER) || defined(__WIN32) |
|
61 if (!mutex) |
|
62 { |
|
63 mutex = new CRITICAL_SECTION(); |
|
64 InitializeCriticalSection(mutex); |
|
65 } |
|
66 #else |
|
67 if (!mutex) |
|
68 { |
|
69 mutex = new pthread_mutex_t(); |
|
70 pthread_mutex_init(mutex, NULL); |
|
71 } |
|
72 #endif |
|
73 |
|
74 if (vm) |
|
75 set_vm(vm, vm_env); |
|
76 else |
|
77 this->vm = NULL; |
|
78 } |
|
79 |
|
80 void JCCEnv::set_vm(JavaVM *vm, JNIEnv *vm_env) |
|
81 { |
|
82 this->vm = vm; |
|
83 set_vm_env(vm_env); |
|
84 |
|
85 _sys = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/System")); |
|
86 _obj = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/Object")); |
|
87 #ifdef _jcc_lib |
|
88 _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("org/apache/jcc/PythonException")); |
|
89 #else |
|
90 _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/RuntimeException")); |
|
91 #endif |
|
92 _mids = new jmethodID[max_mid]; |
|
93 |
|
94 _mids[mid_sys_identityHashCode] = |
|
95 vm_env->GetStaticMethodID(_sys, "identityHashCode", |
|
96 "(Ljava/lang/Object;)I"); |
|
97 _mids[mid_sys_setProperty] = |
|
98 vm_env->GetStaticMethodID(_sys, "setProperty", |
|
99 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); |
|
100 _mids[mid_sys_getProperty] = |
|
101 vm_env->GetStaticMethodID(_sys, "getProperty", |
|
102 "(Ljava/lang/String;)Ljava/lang/String;"); |
|
103 _mids[mid_obj_toString] = |
|
104 vm_env->GetMethodID(_obj, "toString", |
|
105 "()Ljava/lang/String;"); |
|
106 _mids[mid_obj_hashCode] = |
|
107 vm_env->GetMethodID(_obj, "hashCode", |
|
108 "()I"); |
|
109 _mids[mid_obj_getClass] = |
|
110 vm_env->GetMethodID(_obj, "getClass", |
|
111 "()Ljava/lang/Class;"); |
|
112 |
|
113 _mids[mid_iterator_next] = |
|
114 vm_env->GetMethodID(vm_env->FindClass("java/util/Iterator"), |
|
115 "next", "()Ljava/lang/Object;"); |
|
116 _mids[mid_enumeration_nextElement] = |
|
117 vm_env->GetMethodID(vm_env->FindClass("java/util/Enumeration"), |
|
118 "nextElement", "()Ljava/lang/Object;"); |
|
119 } |
|
120 |
|
121 #if defined(_MSC_VER) || defined(__WIN32) |
|
122 |
|
123 void JCCEnv::set_vm_env(JNIEnv *vm_env) |
|
124 { |
|
125 if (!VM_ENV) |
|
126 VM_ENV = TlsAlloc(); |
|
127 TlsSetValue(VM_ENV, (LPVOID) vm_env); |
|
128 } |
|
129 |
|
130 #else |
|
131 |
|
132 void JCCEnv::set_vm_env(JNIEnv *vm_env) |
|
133 { |
|
134 if (!VM_ENV) |
|
135 pthread_key_create(&VM_ENV, NULL); |
|
136 pthread_setspecific(VM_ENV, (void *) vm_env); |
|
137 } |
|
138 |
|
139 #endif |
|
140 |
|
141 jint JCCEnv::getJNIVersion() const |
|
142 { |
|
143 return get_vm_env()->GetVersion(); |
|
144 } |
|
145 |
|
146 jstring JCCEnv::getJavaVersion() const |
|
147 { |
|
148 return (jstring) |
|
149 callStaticObjectMethod(_sys, _mids[mid_sys_getProperty], |
|
150 get_vm_env()->NewStringUTF("java.version")); |
|
151 } |
|
152 |
|
153 jobject JCCEnv::iteratorNext(jobject obj) const |
|
154 { |
|
155 return callObjectMethod(obj, _mids[mid_iterator_next]); |
|
156 } |
|
157 |
|
158 jobject JCCEnv::enumerationNext(jobject obj) const |
|
159 { |
|
160 return callObjectMethod(obj, _mids[mid_enumeration_nextElement]); |
|
161 } |
|
162 |
|
163 jclass JCCEnv::findClass(const char *className) const |
|
164 { |
|
165 jclass cls = NULL; |
|
166 |
|
167 if (vm) |
|
168 { |
|
169 JNIEnv *vm_env = get_vm_env(); |
|
170 |
|
171 if (vm_env) |
|
172 cls = vm_env->FindClass(className); |
|
173 #ifdef PYTHON |
|
174 else |
|
175 { |
|
176 PythonGIL gil; |
|
177 |
|
178 PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first"); |
|
179 throw pythonError(NULL); |
|
180 } |
|
181 #else |
|
182 else |
|
183 throw exception(NULL); |
|
184 #endif |
|
185 } |
|
186 #ifdef PYTHON |
|
187 else |
|
188 { |
|
189 PythonGIL gil; |
|
190 |
|
191 PyErr_SetString(PyExc_RuntimeError, "initVM() must be called first"); |
|
192 throw pythonError(NULL); |
|
193 } |
|
194 #else |
|
195 else |
|
196 throw exception(NULL); |
|
197 #endif |
|
198 |
|
199 reportException(); |
|
200 |
|
201 return cls; |
|
202 } |
|
203 |
|
204 void JCCEnv::registerNatives(jclass cls, JNINativeMethod *methods, int n) const |
|
205 { |
|
206 get_vm_env()->RegisterNatives(cls, methods, n); |
|
207 } |
|
208 |
|
209 jobject JCCEnv::newGlobalRef(jobject obj, int id) |
|
210 { |
|
211 if (obj) |
|
212 { |
|
213 if (id) /* zero when weak global ref is desired */ |
|
214 { |
|
215 lock locked; |
|
216 |
|
217 for (std::multimap<int, countedRef>::iterator iter = refs.find(id); |
|
218 iter != refs.end(); |
|
219 iter++) { |
|
220 if (iter->first != id) |
|
221 break; |
|
222 if (isSame(obj, iter->second.global)) |
|
223 { |
|
224 /* If it's in the table but not the same reference, |
|
225 * it must be a local reference and must be deleted. |
|
226 */ |
|
227 if (obj != iter->second.global) |
|
228 get_vm_env()->DeleteLocalRef(obj); |
|
229 |
|
230 iter->second.count += 1; |
|
231 return iter->second.global; |
|
232 } |
|
233 } |
|
234 |
|
235 JNIEnv *vm_env = get_vm_env(); |
|
236 countedRef ref; |
|
237 |
|
238 ref.global = vm_env->NewGlobalRef(obj); |
|
239 ref.count = 1; |
|
240 refs.insert(std::pair<const int, countedRef>(id, ref)); |
|
241 vm_env->DeleteLocalRef(obj); |
|
242 |
|
243 return ref.global; |
|
244 } |
|
245 else |
|
246 return (jobject) get_vm_env()->NewWeakGlobalRef(obj); |
|
247 } |
|
248 |
|
249 return NULL; |
|
250 } |
|
251 |
|
252 jobject JCCEnv::deleteGlobalRef(jobject obj, int id) |
|
253 { |
|
254 if (obj) |
|
255 { |
|
256 if (id) /* zero when obj is weak global ref */ |
|
257 { |
|
258 lock locked; |
|
259 |
|
260 for (std::multimap<int, countedRef>::iterator iter = refs.find(id); |
|
261 iter != refs.end(); |
|
262 iter++) { |
|
263 if (iter->first != id) |
|
264 break; |
|
265 if (isSame(obj, iter->second.global)) |
|
266 { |
|
267 if (iter->second.count == 1) |
|
268 { |
|
269 get_vm_env()->DeleteGlobalRef(iter->second.global); |
|
270 refs.erase(iter); |
|
271 } |
|
272 else |
|
273 iter->second.count -= 1; |
|
274 |
|
275 return NULL; |
|
276 } |
|
277 } |
|
278 |
|
279 printf("deleting non-existent ref: 0x%x\n", id); |
|
280 } |
|
281 else |
|
282 get_vm_env()->DeleteWeakGlobalRef((jweak) obj); |
|
283 } |
|
284 |
|
285 return NULL; |
|
286 } |
|
287 |
|
288 jobject JCCEnv::newObject(jclass (*initializeClass)(), jmethodID **mids, |
|
289 int m, ...) |
|
290 { |
|
291 jclass cls = (*initializeClass)(); |
|
292 JNIEnv *vm_env = get_vm_env(); |
|
293 jobject obj; |
|
294 |
|
295 if (vm_env) |
|
296 { |
|
297 va_list ap; |
|
298 |
|
299 va_start(ap, m); |
|
300 obj = vm_env->NewObjectV(cls, (*mids)[m], ap); |
|
301 va_end(ap); |
|
302 } |
|
303 #ifdef PYTHON |
|
304 else |
|
305 { |
|
306 PythonGIL gil; |
|
307 |
|
308 PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first"); |
|
309 throw pythonError(NULL); |
|
310 } |
|
311 #else |
|
312 else |
|
313 throw exception(NULL); |
|
314 #endif |
|
315 |
|
316 reportException(); |
|
317 |
|
318 return obj; |
|
319 } |
|
320 |
|
321 jobjectArray JCCEnv::newObjectArray(jclass cls, int size) |
|
322 { |
|
323 jobjectArray array = get_vm_env()->NewObjectArray(size, cls, NULL); |
|
324 |
|
325 reportException(); |
|
326 return array; |
|
327 } |
|
328 |
|
329 void JCCEnv::setObjectArrayElement(jobjectArray array, int n, |
|
330 jobject obj) const |
|
331 { |
|
332 get_vm_env()->SetObjectArrayElement(array, n, obj); |
|
333 reportException(); |
|
334 } |
|
335 |
|
336 jobject JCCEnv::getObjectArrayElement(jobjectArray array, int n) const |
|
337 { |
|
338 jobject obj = get_vm_env()->GetObjectArrayElement(array, n); |
|
339 |
|
340 reportException(); |
|
341 return obj; |
|
342 } |
|
343 |
|
344 int JCCEnv::getArrayLength(jarray array) const |
|
345 { |
|
346 int len = get_vm_env()->GetArrayLength(array); |
|
347 |
|
348 reportException(); |
|
349 return len; |
|
350 } |
|
351 |
|
352 #ifdef PYTHON |
|
353 jclass JCCEnv::getPythonExceptionClass() const |
|
354 { |
|
355 return _thr; |
|
356 } |
|
357 #endif |
|
358 |
|
359 void JCCEnv::reportException() const |
|
360 { |
|
361 JNIEnv *vm_env = get_vm_env(); |
|
362 jthrowable throwable = vm_env->ExceptionOccurred(); |
|
363 |
|
364 if (throwable) |
|
365 { |
|
366 if (!env->handlers) |
|
367 vm_env->ExceptionDescribe(); |
|
368 |
|
369 vm_env->ExceptionClear(); |
|
370 |
|
371 #ifdef PYTHON |
|
372 PythonGIL gil; |
|
373 |
|
374 if (PyErr_Occurred()) |
|
375 { |
|
376 /* _thr is PythonException ifdef _jcc_lib (shared mode) |
|
377 * if not shared mode, _thr is RuntimeException |
|
378 */ |
|
379 jobject cls = (jobject) vm_env->GetObjectClass(throwable); |
|
380 |
|
381 if (vm_env->IsSameObject(cls, _thr)) |
|
382 throw pythonError(throwable); |
|
383 } |
|
384 #endif |
|
385 |
|
386 throw exception(throwable); |
|
387 } |
|
388 } |
|
389 |
|
390 |
|
391 #define DEFINE_CALL(jtype, Type) \ |
|
392 jtype JCCEnv::call##Type##Method(jobject obj, \ |
|
393 jmethodID mid, ...) const \ |
|
394 { \ |
|
395 va_list ap; \ |
|
396 jtype result; \ |
|
397 \ |
|
398 va_start(ap, mid); \ |
|
399 result = get_vm_env()->Call##Type##MethodV(obj, mid, ap); \ |
|
400 va_end(ap); \ |
|
401 \ |
|
402 reportException(); \ |
|
403 \ |
|
404 return result; \ |
|
405 } |
|
406 |
|
407 #define DEFINE_NONVIRTUAL_CALL(jtype, Type) \ |
|
408 jtype JCCEnv::callNonvirtual##Type##Method(jobject obj, jclass cls, \ |
|
409 jmethodID mid, ...) const \ |
|
410 { \ |
|
411 va_list ap; \ |
|
412 jtype result; \ |
|
413 \ |
|
414 va_start(ap, mid); \ |
|
415 result = get_vm_env()->CallNonvirtual##Type##MethodV(obj, cls, \ |
|
416 mid, ap); \ |
|
417 va_end(ap); \ |
|
418 \ |
|
419 reportException(); \ |
|
420 \ |
|
421 return result; \ |
|
422 } |
|
423 |
|
424 #define DEFINE_STATIC_CALL(jtype, Type) \ |
|
425 jtype JCCEnv::callStatic##Type##Method(jclass cls, \ |
|
426 jmethodID mid, ...) const \ |
|
427 { \ |
|
428 va_list ap; \ |
|
429 jtype result; \ |
|
430 \ |
|
431 va_start(ap, mid); \ |
|
432 result = get_vm_env()->CallStatic##Type##MethodV(cls, mid, ap); \ |
|
433 va_end(ap); \ |
|
434 \ |
|
435 reportException(); \ |
|
436 \ |
|
437 return result; \ |
|
438 } |
|
439 |
|
440 DEFINE_CALL(jobject, Object) |
|
441 DEFINE_CALL(jboolean, Boolean) |
|
442 DEFINE_CALL(jbyte, Byte) |
|
443 DEFINE_CALL(jchar, Char) |
|
444 DEFINE_CALL(jdouble, Double) |
|
445 DEFINE_CALL(jfloat, Float) |
|
446 DEFINE_CALL(jint, Int) |
|
447 DEFINE_CALL(jlong, Long) |
|
448 DEFINE_CALL(jshort, Short) |
|
449 |
|
450 DEFINE_NONVIRTUAL_CALL(jobject, Object) |
|
451 DEFINE_NONVIRTUAL_CALL(jboolean, Boolean) |
|
452 DEFINE_NONVIRTUAL_CALL(jbyte, Byte) |
|
453 DEFINE_NONVIRTUAL_CALL(jchar, Char) |
|
454 DEFINE_NONVIRTUAL_CALL(jdouble, Double) |
|
455 DEFINE_NONVIRTUAL_CALL(jfloat, Float) |
|
456 DEFINE_NONVIRTUAL_CALL(jint, Int) |
|
457 DEFINE_NONVIRTUAL_CALL(jlong, Long) |
|
458 DEFINE_NONVIRTUAL_CALL(jshort, Short) |
|
459 |
|
460 DEFINE_STATIC_CALL(jobject, Object) |
|
461 DEFINE_STATIC_CALL(jboolean, Boolean) |
|
462 DEFINE_STATIC_CALL(jbyte, Byte) |
|
463 DEFINE_STATIC_CALL(jchar, Char) |
|
464 DEFINE_STATIC_CALL(jdouble, Double) |
|
465 DEFINE_STATIC_CALL(jfloat, Float) |
|
466 DEFINE_STATIC_CALL(jint, Int) |
|
467 DEFINE_STATIC_CALL(jlong, Long) |
|
468 DEFINE_STATIC_CALL(jshort, Short) |
|
469 |
|
470 void JCCEnv::callVoidMethod(jobject obj, jmethodID mid, ...) const |
|
471 { |
|
472 va_list ap; |
|
473 |
|
474 va_start(ap, mid); |
|
475 get_vm_env()->CallVoidMethodV(obj, mid, ap); |
|
476 va_end(ap); |
|
477 |
|
478 reportException(); |
|
479 } |
|
480 |
|
481 void JCCEnv::callNonvirtualVoidMethod(jobject obj, jclass cls, |
|
482 jmethodID mid, ...) const |
|
483 { |
|
484 va_list ap; |
|
485 |
|
486 va_start(ap, mid); |
|
487 get_vm_env()->CallNonvirtualVoidMethodV(obj, cls, mid, ap); |
|
488 va_end(ap); |
|
489 |
|
490 reportException(); |
|
491 } |
|
492 |
|
493 void JCCEnv::callStaticVoidMethod(jclass cls, jmethodID mid, ...) const |
|
494 { |
|
495 va_list ap; |
|
496 |
|
497 va_start(ap, mid); |
|
498 get_vm_env()->CallStaticVoidMethodV(cls, mid, ap); |
|
499 va_end(ap); |
|
500 |
|
501 reportException(); |
|
502 } |
|
503 |
|
504 |
|
505 jmethodID JCCEnv::getMethodID(jclass cls, const char *name, |
|
506 const char *signature) const |
|
507 { |
|
508 jmethodID id = get_vm_env()->GetMethodID(cls, name, signature); |
|
509 |
|
510 reportException(); |
|
511 |
|
512 return id; |
|
513 } |
|
514 |
|
515 jfieldID JCCEnv::getFieldID(jclass cls, const char *name, |
|
516 const char *signature) const |
|
517 { |
|
518 jfieldID id = get_vm_env()->GetFieldID(cls, name, signature); |
|
519 |
|
520 reportException(); |
|
521 |
|
522 return id; |
|
523 } |
|
524 |
|
525 |
|
526 jmethodID JCCEnv::getStaticMethodID(jclass cls, const char *name, |
|
527 const char *signature) const |
|
528 { |
|
529 jmethodID id = get_vm_env()->GetStaticMethodID(cls, name, signature); |
|
530 |
|
531 reportException(); |
|
532 |
|
533 return id; |
|
534 } |
|
535 |
|
536 jobject JCCEnv::getStaticObjectField(jclass cls, const char *name, |
|
537 const char *signature) const |
|
538 { |
|
539 JNIEnv *vm_env = get_vm_env(); |
|
540 jfieldID id = vm_env->GetStaticFieldID(cls, name, signature); |
|
541 |
|
542 reportException(); |
|
543 |
|
544 return vm_env->GetStaticObjectField(cls, id); |
|
545 } |
|
546 |
|
547 #define DEFINE_GET_STATIC_FIELD(jtype, Type, signature) \ |
|
548 jtype JCCEnv::getStatic##Type##Field(jclass cls, \ |
|
549 const char *name) const \ |
|
550 { \ |
|
551 JNIEnv *vm_env = get_vm_env(); \ |
|
552 jfieldID id = vm_env->GetStaticFieldID(cls, name, #signature); \ |
|
553 reportException(); \ |
|
554 return vm_env->GetStatic##Type##Field(cls, id); \ |
|
555 } |
|
556 |
|
557 DEFINE_GET_STATIC_FIELD(jboolean, Boolean, Z) |
|
558 DEFINE_GET_STATIC_FIELD(jbyte, Byte, B) |
|
559 DEFINE_GET_STATIC_FIELD(jchar, Char, C) |
|
560 DEFINE_GET_STATIC_FIELD(jdouble, Double, D) |
|
561 DEFINE_GET_STATIC_FIELD(jfloat, Float, F) |
|
562 DEFINE_GET_STATIC_FIELD(jint, Int, I) |
|
563 DEFINE_GET_STATIC_FIELD(jlong, Long, J) |
|
564 DEFINE_GET_STATIC_FIELD(jshort, Short, S) |
|
565 |
|
566 #define DEFINE_GET_FIELD(jtype, Type) \ |
|
567 jtype JCCEnv::get##Type##Field(jobject obj, jfieldID id) const \ |
|
568 { \ |
|
569 jtype value = get_vm_env()->Get##Type##Field(obj, id); \ |
|
570 reportException(); \ |
|
571 return value; \ |
|
572 } |
|
573 |
|
574 DEFINE_GET_FIELD(jobject, Object) |
|
575 DEFINE_GET_FIELD(jboolean, Boolean) |
|
576 DEFINE_GET_FIELD(jbyte, Byte) |
|
577 DEFINE_GET_FIELD(jchar, Char) |
|
578 DEFINE_GET_FIELD(jdouble, Double) |
|
579 DEFINE_GET_FIELD(jfloat, Float) |
|
580 DEFINE_GET_FIELD(jint, Int) |
|
581 DEFINE_GET_FIELD(jlong, Long) |
|
582 DEFINE_GET_FIELD(jshort, Short) |
|
583 |
|
584 #define DEFINE_SET_FIELD(jtype, Type) \ |
|
585 void JCCEnv::set##Type##Field(jobject obj, jfieldID id, \ |
|
586 jtype value) const \ |
|
587 { \ |
|
588 get_vm_env()->Set##Type##Field(obj, id, value); \ |
|
589 reportException(); \ |
|
590 } |
|
591 |
|
592 DEFINE_SET_FIELD(jobject, Object) |
|
593 DEFINE_SET_FIELD(jboolean, Boolean) |
|
594 DEFINE_SET_FIELD(jbyte, Byte) |
|
595 DEFINE_SET_FIELD(jchar, Char) |
|
596 DEFINE_SET_FIELD(jdouble, Double) |
|
597 DEFINE_SET_FIELD(jfloat, Float) |
|
598 DEFINE_SET_FIELD(jint, Int) |
|
599 DEFINE_SET_FIELD(jlong, Long) |
|
600 DEFINE_SET_FIELD(jshort, Short) |
|
601 |
|
602 void JCCEnv::setClassPath(const char *classPath) |
|
603 { |
|
604 JNIEnv *vm_env = get_vm_env(); |
|
605 jclass _ucl = (jclass) vm_env->FindClass("java/net/URLClassLoader"); |
|
606 jclass _fil = (jclass) vm_env->FindClass("java/io/File"); |
|
607 jmethodID mid = vm_env->GetStaticMethodID(_ucl, "getSystemClassLoader", |
|
608 "()Ljava/lang/ClassLoader;"); |
|
609 jobject classLoader = vm_env->CallStaticObjectMethod(_ucl, mid); |
|
610 jmethodID mf = vm_env->GetMethodID(_fil, "<init>", "(Ljava/lang/String;)V"); |
|
611 jmethodID mu = vm_env->GetMethodID(_fil, "toURL", "()Ljava/net/URL;"); |
|
612 jmethodID ma = vm_env->GetMethodID(_ucl, "addURL", "(Ljava/net/URL;)V"); |
|
613 #ifdef WINDOWS |
|
614 char *pathsep = ";"; |
|
615 #else |
|
616 char *pathsep = ":"; |
|
617 #endif |
|
618 char *path = strdup(classPath); |
|
619 |
|
620 for (char *cp = strtok(path, pathsep); |
|
621 cp != NULL; |
|
622 cp = strtok(NULL, pathsep)) { |
|
623 jstring string = vm_env->NewStringUTF(cp); |
|
624 jobject file = vm_env->NewObject(_fil, mf, string); |
|
625 jobject url = vm_env->CallObjectMethod(file, mu); |
|
626 |
|
627 vm_env->CallVoidMethod(classLoader, ma, url); |
|
628 } |
|
629 free(path); |
|
630 } |
|
631 |
|
632 jstring JCCEnv::fromUTF(const char *bytes) const |
|
633 { |
|
634 jstring str = get_vm_env()->NewStringUTF(bytes); |
|
635 |
|
636 reportException(); |
|
637 |
|
638 return str; |
|
639 } |
|
640 |
|
641 char *JCCEnv::toUTF(jstring str) const |
|
642 { |
|
643 JNIEnv *vm_env = get_vm_env(); |
|
644 int len = vm_env->GetStringUTFLength(str); |
|
645 char *bytes = new char[len + 1]; |
|
646 jboolean isCopy = 0; |
|
647 const char *utf = vm_env->GetStringUTFChars(str, &isCopy); |
|
648 |
|
649 if (!bytes) |
|
650 return NULL; |
|
651 |
|
652 memcpy(bytes, utf, len); |
|
653 bytes[len] = '\0'; |
|
654 |
|
655 vm_env->ReleaseStringUTFChars(str, utf); |
|
656 |
|
657 return bytes; |
|
658 } |
|
659 |
|
660 char *JCCEnv::toString(jobject obj) const |
|
661 { |
|
662 return obj |
|
663 ? toUTF((jstring) callObjectMethod(obj, _mids[mid_obj_toString])) |
|
664 : NULL; |
|
665 } |
|
666 |
|
667 char *JCCEnv::getClassName(jobject obj) const |
|
668 { |
|
669 return obj |
|
670 ? toString(callObjectMethod(obj, _mids[mid_obj_getClass])) |
|
671 : NULL; |
|
672 } |
|
673 |
|
674 #ifdef PYTHON |
|
675 |
|
676 jstring JCCEnv::fromPyString(PyObject *object) const |
|
677 { |
|
678 if (object == Py_None) |
|
679 return NULL; |
|
680 |
|
681 if (PyUnicode_Check(object)) |
|
682 { |
|
683 if (sizeof(Py_UNICODE) == sizeof(jchar)) |
|
684 { |
|
685 jchar *buf = (jchar *) PyUnicode_AS_UNICODE(object); |
|
686 jsize len = (jsize) PyUnicode_GET_SIZE(object); |
|
687 |
|
688 return get_vm_env()->NewString(buf, len); |
|
689 } |
|
690 else |
|
691 { |
|
692 jsize len = PyUnicode_GET_SIZE(object); |
|
693 Py_UNICODE *pchars = PyUnicode_AS_UNICODE(object); |
|
694 jchar *jchars = new jchar[len]; |
|
695 jstring str; |
|
696 |
|
697 for (int i = 0; i < len; i++) |
|
698 jchars[i] = (jchar) pchars[i]; |
|
699 |
|
700 str = get_vm_env()->NewString(jchars, len); |
|
701 delete jchars; |
|
702 |
|
703 return str; |
|
704 } |
|
705 } |
|
706 else if (PyString_Check(object)) |
|
707 return fromUTF(PyString_AS_STRING(object)); |
|
708 else |
|
709 { |
|
710 PyObject *tuple = Py_BuildValue("(sO)", "expected a string", object); |
|
711 |
|
712 PyErr_SetObject(PyExc_TypeError, tuple); |
|
713 Py_DECREF(tuple); |
|
714 |
|
715 return NULL; |
|
716 } |
|
717 } |
|
718 |
|
719 PyObject *JCCEnv::fromJString(jstring js, int delete_local_ref) const |
|
720 { |
|
721 if (!js) |
|
722 Py_RETURN_NONE; |
|
723 |
|
724 JNIEnv *vm_env = get_vm_env(); |
|
725 PyObject *string; |
|
726 |
|
727 if (sizeof(Py_UNICODE) == sizeof(jchar)) |
|
728 { |
|
729 jboolean isCopy; |
|
730 const jchar *buf = vm_env->GetStringChars(js, &isCopy); |
|
731 jsize len = vm_env->GetStringLength(js); |
|
732 |
|
733 string = PyUnicode_FromUnicode((const Py_UNICODE *) buf, len); |
|
734 vm_env->ReleaseStringChars(js, buf); |
|
735 } |
|
736 else |
|
737 { |
|
738 jsize len = vm_env->GetStringLength(js); |
|
739 |
|
740 string = PyUnicode_FromUnicode(NULL, len); |
|
741 if (string) |
|
742 { |
|
743 jboolean isCopy; |
|
744 const jchar *jchars = vm_env->GetStringChars(js, &isCopy); |
|
745 Py_UNICODE *pchars = PyUnicode_AS_UNICODE(string); |
|
746 |
|
747 for (int i = 0; i < len; i++) |
|
748 pchars[i] = (Py_UNICODE) jchars[i]; |
|
749 |
|
750 vm_env->ReleaseStringChars(js, jchars); |
|
751 } |
|
752 } |
|
753 |
|
754 if (delete_local_ref) |
|
755 vm_env->DeleteLocalRef((jobject) js); |
|
756 |
|
757 return string; |
|
758 } |
|
759 |
|
760 |
|
761 /* may be called from finalizer thread which has no vm_env thread local */ |
|
762 void JCCEnv::finalizeObject(JNIEnv *jenv, PyObject *obj) |
|
763 { |
|
764 PythonGIL gil; |
|
765 |
|
766 set_vm_env(jenv); |
|
767 Py_DECREF(obj); |
|
768 } |
|
769 |
|
770 #endif /* PYTHON */ |