PyLucene 3.4.0-1 import
[pylucene.git] / jcc / jcc / sources / JCCEnv.cpp
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 #if defined(_MSC_VER) || defined(__WIN32)
22 _DLL_EXPORT DWORD VM_ENV = 0;
23 #else
24 pthread_key_t JCCEnv::VM_ENV = (pthread_key_t) NULL;
25 #endif
26
27 #if defined(_MSC_VER) || defined(__WIN32)
28
29 static CRITICAL_SECTION *mutex = NULL;
30
31 class lock {
32 public:
33     lock() {
34         EnterCriticalSection(mutex);
35     }
36     virtual ~lock() {
37         LeaveCriticalSection(mutex);
38     }
39 };
40
41 #else
42
43 static pthread_mutex_t *mutex = NULL;
44
45 class lock {
46 public:
47     lock() {
48         pthread_mutex_lock(mutex);
49     }
50     virtual ~lock() {
51         pthread_mutex_unlock(mutex);
52     }
53 };
54
55 #endif
56
57 JCCEnv::JCCEnv(JavaVM *vm, JNIEnv *vm_env)
58 {
59 #if defined(_MSC_VER) || defined(__WIN32)
60     if (!mutex)
61     {
62         mutex = new CRITICAL_SECTION();
63         InitializeCriticalSection(mutex);
64     }
65 #else
66     if (!mutex)
67     {
68         mutex = new pthread_mutex_t();
69         pthread_mutex_init(mutex, NULL);
70     }
71 #endif
72
73     if (vm)
74         set_vm(vm, vm_env);
75     else
76         this->vm = NULL;
77 }
78
79 void JCCEnv::set_vm(JavaVM *vm, JNIEnv *vm_env)
80 {
81     this->vm = vm;
82     set_vm_env(vm_env);
83
84     _sys = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/System"));
85     _obj = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/Object"));
86 #ifdef _jcc_lib
87     _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("org/apache/jcc/PythonException"));
88 #else
89     _thr = (jclass) vm_env->NewGlobalRef(vm_env->FindClass("java/lang/RuntimeException"));
90 #endif
91
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
114     jclass iterable = vm_env->FindClass("java/lang/Iterable");
115
116     if (iterable == NULL) /* JDK < 1.5 */
117     {
118         vm_env->ExceptionClear();
119         _mids[mid_iterator] = NULL;
120         _mids[mid_iterator_next] = NULL;
121     }
122     else
123     {
124         _mids[mid_iterator] =
125             vm_env->GetMethodID(iterable,
126                                 "iterator", "()Ljava/util/Iterator;");
127         _mids[mid_iterator_next] =
128             vm_env->GetMethodID(vm_env->FindClass("java/util/Iterator"),
129                                 "next", "()Ljava/lang/Object;");
130     }
131
132
133     _mids[mid_enumeration_nextElement] =
134         vm_env->GetMethodID(vm_env->FindClass("java/util/Enumeration"),
135                             "nextElement", "()Ljava/lang/Object;");
136
137     _mids[mid_Boolean_booleanValue] =
138         vm_env->GetMethodID(vm_env->FindClass("java/lang/Boolean"),
139                             "booleanValue", "()Z");
140     _mids[mid_Byte_byteValue] = 
141         vm_env->GetMethodID(vm_env->FindClass("java/lang/Byte"),
142                             "byteValue", "()B");
143     _mids[mid_Character_charValue] =
144         vm_env->GetMethodID(vm_env->FindClass("java/lang/Character"),
145                             "charValue", "()C");
146     _mids[mid_Double_doubleValue] = 
147         vm_env->GetMethodID(vm_env->FindClass("java/lang/Double"),
148                             "doubleValue", "()D");
149     _mids[mid_Float_floatValue] =
150         vm_env->GetMethodID(vm_env->FindClass("java/lang/Float"),
151                             "floatValue", "()F");
152     _mids[mid_Integer_intValue] = 
153         vm_env->GetMethodID(vm_env->FindClass("java/lang/Integer"),
154                             "intValue", "()I");
155     _mids[mid_Long_longValue] = 
156         vm_env->GetMethodID(vm_env->FindClass("java/lang/Long"),
157                             "longValue", "()J");
158     _mids[mid_Short_shortValue] = 
159         vm_env->GetMethodID(vm_env->FindClass("java/lang/Short"),
160                             "shortValue", "()S");
161 }
162
163 int JCCEnv::attachCurrentThread(char *name, int asDaemon)
164 {
165     JNIEnv *jenv = NULL;
166     JavaVMAttachArgs attach = {
167         JNI_VERSION_1_4, name, NULL
168     };
169     int result;
170
171     if (asDaemon)
172         result = vm->AttachCurrentThreadAsDaemon((void **) &jenv, &attach);
173     else
174         result = vm->AttachCurrentThread((void **) &jenv, &attach);
175
176     set_vm_env(jenv);
177
178     return result;
179 }
180
181 #if defined(_MSC_VER) || defined(__WIN32)
182
183 void JCCEnv::set_vm_env(JNIEnv *vm_env)
184 {
185     if (!VM_ENV)
186         VM_ENV = TlsAlloc();
187     TlsSetValue(VM_ENV, (LPVOID) vm_env);
188 }
189
190 #else
191
192 void JCCEnv::set_vm_env(JNIEnv *vm_env)
193 {
194     if (!VM_ENV)
195         pthread_key_create(&VM_ENV, NULL);
196     pthread_setspecific(VM_ENV, (void *) vm_env);
197 }
198
199 #endif
200
201 jint JCCEnv::getJNIVersion() const
202 {
203     return get_vm_env()->GetVersion();
204 }
205
206 jstring JCCEnv::getJavaVersion() const
207 {
208     return (jstring)
209         callStaticObjectMethod(_sys, _mids[mid_sys_getProperty],
210                                get_vm_env()->NewStringUTF("java.version"));
211 }
212
213 jobject JCCEnv::iterator(jobject obj) const
214 {
215     return callObjectMethod(obj, _mids[mid_iterator]);
216 }
217
218 jobject JCCEnv::iteratorNext(jobject obj) const
219 {
220     return callObjectMethod(obj, _mids[mid_iterator_next]);
221 }
222
223 jobject JCCEnv::enumerationNext(jobject obj) const
224 {
225     return callObjectMethod(obj, _mids[mid_enumeration_nextElement]);
226 }
227
228 jboolean JCCEnv::isInstanceOf(jobject obj, getclassfn initializeClass) const
229 {
230     return get_vm_env()->IsInstanceOf(obj, (*initializeClass)());
231 }
232
233 jclass JCCEnv::findClass(const char *className) const
234 {
235     jclass cls = NULL;
236
237     if (vm)
238     {
239         JNIEnv *vm_env = get_vm_env();
240
241         if (vm_env)
242             cls = vm_env->FindClass(className);
243 #ifdef PYTHON
244         else
245         {
246             PythonGIL gil;
247
248             PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first");
249             throw _EXC_PYTHON;
250         }
251 #else
252         else
253             throw _EXC_JAVA;
254 #endif
255     }
256 #ifdef PYTHON
257     else
258     {
259         PythonGIL gil;
260
261         PyErr_SetString(PyExc_RuntimeError, "initVM() must be called first");
262         throw _EXC_PYTHON;
263     }
264 #else
265     else
266         throw _EXC_JAVA;
267 #endif
268
269     reportException();
270
271     return cls;
272 }
273
274 void JCCEnv::registerNatives(jclass cls, JNINativeMethod *methods, int n) const
275 {
276     get_vm_env()->RegisterNatives(cls, methods, n);
277 }
278
279 jobject JCCEnv::newGlobalRef(jobject obj, int id)
280 {
281     if (obj)
282     {
283         if (id)  /* zero when weak global ref is desired */
284         {
285             lock locked;
286
287             for (std::multimap<int, countedRef>::iterator iter = refs.find(id);
288                  iter != refs.end();
289                  iter++) {
290                 if (iter->first != id)
291                     break;
292                 if (isSame(obj, iter->second.global))
293                 {
294                     /* If it's in the table but not the same reference,
295                      * it must be a local reference and must be deleted.
296                      */
297                     if (obj != iter->second.global)
298                         get_vm_env()->DeleteLocalRef(obj);
299                         
300                     iter->second.count += 1;
301                     return iter->second.global;
302                 }
303             }
304
305             JNIEnv *vm_env = get_vm_env();
306             countedRef ref;
307
308             ref.global = vm_env->NewGlobalRef(obj);
309             ref.count = 1;
310             refs.insert(std::pair<const int, countedRef>(id, ref));
311             vm_env->DeleteLocalRef(obj);
312
313             return ref.global;
314         }
315         else
316             return (jobject) get_vm_env()->NewWeakGlobalRef(obj);
317     }
318
319     return NULL;
320 }
321
322 jobject JCCEnv::deleteGlobalRef(jobject obj, int id)
323 {
324     if (obj)
325     {
326         if (id)  /* zero when obj is weak global ref */
327         {
328             lock locked;
329
330             for (std::multimap<int, countedRef>::iterator iter = refs.find(id);
331                  iter != refs.end();
332                  iter++) {
333                 if (iter->first != id)
334                     break;
335                 if (isSame(obj, iter->second.global))
336                 {
337                     if (iter->second.count == 1)
338                     {
339                         JNIEnv *vm_env = get_vm_env();
340
341                         if (!vm_env)
342                         {
343                             /* Python's cyclic garbage collector may remove
344                              * an object inside a thread that is not attached
345                              * to the JVM. This makes sure the JVM doesn't
346                              * segfault.
347                              */
348                             attachCurrentThread(NULL, 0);
349                             vm_env = get_vm_env();
350                         }
351
352                         vm_env->DeleteGlobalRef(iter->second.global);
353                         refs.erase(iter);
354                     }
355                     else
356                         iter->second.count -= 1;
357
358                     return NULL;
359                 }
360             }
361
362             printf("deleting non-existent ref: 0x%x\n", id);
363         }
364         else
365             get_vm_env()->DeleteWeakGlobalRef((jweak) obj);
366     }
367
368     return NULL;
369 }
370
371 jobject JCCEnv::newObject(getclassfn initializeClass, jmethodID **mids,
372                           int m, ...)
373 {
374     jclass cls = (*initializeClass)();
375     JNIEnv *vm_env = get_vm_env();
376     jobject obj;
377
378     if (vm_env)
379     {
380         va_list ap;
381
382         va_start(ap, m);
383         obj = vm_env->NewObjectV(cls, (*mids)[m], ap);
384         va_end(ap);
385     }
386 #ifdef PYTHON
387     else
388     {
389         PythonGIL gil;
390
391         PyErr_SetString(PyExc_RuntimeError, "attachCurrentThread() must be called first");
392         throw _EXC_PYTHON;
393     }
394 #else
395     else
396         throw _EXC_JAVA;
397 #endif
398
399     reportException();
400
401     return obj;
402 }
403
404 jobjectArray JCCEnv::newObjectArray(jclass cls, int size)
405 {
406     jobjectArray array = get_vm_env()->NewObjectArray(size, cls, NULL);
407
408     reportException();
409     return array;
410 }
411
412 void JCCEnv::setObjectArrayElement(jobjectArray array, int n,
413                                    jobject obj) const
414 {
415     get_vm_env()->SetObjectArrayElement(array, n, obj);
416     reportException();
417 }
418
419 jobject JCCEnv::getObjectArrayElement(jobjectArray array, int n) const
420 {
421     jobject obj = get_vm_env()->GetObjectArrayElement(array, n);
422
423     reportException();
424     return obj;
425 }
426
427 int JCCEnv::getArrayLength(jarray array) const
428 {
429     int len = get_vm_env()->GetArrayLength(array);
430
431     reportException();
432     return len;
433 }
434
435 #ifdef PYTHON
436 jclass JCCEnv::getPythonExceptionClass() const
437 {
438     return _thr;
439 }
440 #endif
441
442 void JCCEnv::reportException() const
443 {
444     JNIEnv *vm_env = get_vm_env();
445     jthrowable throwable = vm_env->ExceptionOccurred();
446
447     if (throwable)
448     {
449         if (!env->handlers)
450             vm_env->ExceptionDescribe();
451
452 #ifdef PYTHON
453         PythonGIL gil;
454
455         if (PyErr_Occurred())
456         {
457             /* _thr is PythonException ifdef _jcc_lib (shared mode)
458              * if not shared mode, _thr is RuntimeException
459              */
460             jobject cls = (jobject) vm_env->GetObjectClass(throwable);
461
462             if (vm_env->IsSameObject(cls, _thr))
463             {
464 #ifndef _jcc_lib
465                 /* PythonException class is not available without shared mode.
466                  * Python exception information thus gets lost and exception
467                  * is reported via plain Java RuntimeException.
468                  */
469                 PyErr_Clear();
470                 throw _EXC_JAVA;
471 #else
472                 throw _EXC_PYTHON;
473 #endif
474             }
475         }
476 #endif
477
478         throw _EXC_JAVA;
479     }
480 }
481
482
483 #define DEFINE_CALL(jtype, Type)                                         \
484     jtype JCCEnv::call##Type##Method(jobject obj,                        \
485                                      jmethodID mid, ...) const           \
486     {                                                                    \
487         va_list ap;                                                      \
488         jtype result;                                                    \
489                                                                          \
490         va_start(ap, mid);                                               \
491         result = get_vm_env()->Call##Type##MethodV(obj, mid, ap);        \
492         va_end(ap);                                                      \
493                                                                          \
494         reportException();                                               \
495                                                                          \
496         return result;                                                   \
497     }
498
499 #define DEFINE_NONVIRTUAL_CALL(jtype, Type)                              \
500     jtype JCCEnv::callNonvirtual##Type##Method(jobject obj, jclass cls,  \
501                                                jmethodID mid, ...) const \
502     {                                                                    \
503         va_list ap;                                                      \
504         jtype result;                                                    \
505                                                                          \
506         va_start(ap, mid);                                               \
507         result = get_vm_env()->CallNonvirtual##Type##MethodV(obj, cls,   \
508                                                              mid, ap);   \
509         va_end(ap);                                                      \
510                                                                          \
511         reportException();                                               \
512                                                                          \
513         return result;                                                   \
514     }
515
516 #define DEFINE_STATIC_CALL(jtype, Type)                                 \
517     jtype JCCEnv::callStatic##Type##Method(jclass cls,                  \
518                                            jmethodID mid, ...) const    \
519     {                                                                   \
520         va_list ap;                                                     \
521         jtype result;                                                   \
522                                                                         \
523         va_start(ap, mid);                                              \
524         result = get_vm_env()->CallStatic##Type##MethodV(cls, mid, ap); \
525         va_end(ap);                                                     \
526                                                                         \
527         reportException();                                              \
528                                                                         \
529         return result;                                                  \
530     }
531         
532 DEFINE_CALL(jobject, Object)
533 DEFINE_CALL(jboolean, Boolean)
534 DEFINE_CALL(jbyte, Byte)
535 DEFINE_CALL(jchar, Char)
536 DEFINE_CALL(jdouble, Double)
537 DEFINE_CALL(jfloat, Float)
538 DEFINE_CALL(jint, Int)
539 DEFINE_CALL(jlong, Long)
540 DEFINE_CALL(jshort, Short)
541
542 DEFINE_NONVIRTUAL_CALL(jobject, Object)
543 DEFINE_NONVIRTUAL_CALL(jboolean, Boolean)
544 DEFINE_NONVIRTUAL_CALL(jbyte, Byte)
545 DEFINE_NONVIRTUAL_CALL(jchar, Char)
546 DEFINE_NONVIRTUAL_CALL(jdouble, Double)
547 DEFINE_NONVIRTUAL_CALL(jfloat, Float)
548 DEFINE_NONVIRTUAL_CALL(jint, Int)
549 DEFINE_NONVIRTUAL_CALL(jlong, Long)
550 DEFINE_NONVIRTUAL_CALL(jshort, Short)
551
552 DEFINE_STATIC_CALL(jobject, Object)
553 DEFINE_STATIC_CALL(jboolean, Boolean)
554 DEFINE_STATIC_CALL(jbyte, Byte)
555 DEFINE_STATIC_CALL(jchar, Char)
556 DEFINE_STATIC_CALL(jdouble, Double)
557 DEFINE_STATIC_CALL(jfloat, Float)
558 DEFINE_STATIC_CALL(jint, Int)
559 DEFINE_STATIC_CALL(jlong, Long)
560 DEFINE_STATIC_CALL(jshort, Short)
561
562 void JCCEnv::callVoidMethod(jobject obj, jmethodID mid, ...) const
563 {
564     va_list ap;
565
566     va_start(ap, mid);
567     get_vm_env()->CallVoidMethodV(obj, mid, ap);
568     va_end(ap);
569
570     reportException();
571 }
572
573 void JCCEnv::callNonvirtualVoidMethod(jobject obj, jclass cls,
574                                       jmethodID mid, ...) const
575 {
576     va_list ap;
577
578     va_start(ap, mid);
579     get_vm_env()->CallNonvirtualVoidMethodV(obj, cls, mid, ap);
580     va_end(ap);
581
582     reportException();
583 }
584
585 void JCCEnv::callStaticVoidMethod(jclass cls, jmethodID mid, ...) const
586 {
587     va_list ap;
588
589     va_start(ap, mid);
590     get_vm_env()->CallStaticVoidMethodV(cls, mid, ap);
591     va_end(ap);
592
593     reportException();
594 }
595
596
597 jboolean JCCEnv::booleanValue(jobject obj) const
598 {
599     return get_vm_env()->CallBooleanMethod(obj, _mids[mid_Boolean_booleanValue]);
600 }
601
602 jbyte JCCEnv::byteValue(jobject obj) const
603 {
604     return get_vm_env()->CallByteMethod(obj, _mids[mid_Byte_byteValue]);
605 }
606
607 jchar JCCEnv::charValue(jobject obj) const
608 {
609     return get_vm_env()->CallCharMethod(obj, _mids[mid_Character_charValue]);
610 }
611
612 jdouble JCCEnv::doubleValue(jobject obj) const
613 {
614     return get_vm_env()->CallDoubleMethod(obj, _mids[mid_Double_doubleValue]);
615 }
616
617 jfloat JCCEnv::floatValue(jobject obj) const
618 {
619     return get_vm_env()->CallFloatMethod(obj, _mids[mid_Float_floatValue]);
620 }
621
622 jint JCCEnv::intValue(jobject obj) const
623 {
624     return get_vm_env()->CallIntMethod(obj, _mids[mid_Integer_intValue]);
625 }
626
627 jlong JCCEnv::longValue(jobject obj) const
628 {
629     return get_vm_env()->CallLongMethod(obj, _mids[mid_Long_longValue]);
630 }
631
632 jshort JCCEnv::shortValue(jobject obj) const
633 {
634     return get_vm_env()->CallShortMethod(obj, _mids[mid_Short_shortValue]);
635 }
636
637
638 jmethodID JCCEnv::getMethodID(jclass cls, const char *name,
639                               const char *signature) const
640 {
641     jmethodID id = get_vm_env()->GetMethodID(cls, name, signature);
642
643     reportException();
644
645     return id;
646 }
647
648 jfieldID JCCEnv::getFieldID(jclass cls, const char *name,
649                             const char *signature) const
650 {
651     jfieldID id = get_vm_env()->GetFieldID(cls, name, signature);
652
653     reportException();
654
655     return id;
656 }
657
658
659 jmethodID JCCEnv::getStaticMethodID(jclass cls, const char *name,
660                                     const char *signature) const
661 {
662     jmethodID id = get_vm_env()->GetStaticMethodID(cls, name, signature);
663
664     reportException();
665
666     return id;
667 }
668
669 jobject JCCEnv::getStaticObjectField(jclass cls, const char *name,
670                                      const char *signature) const
671 {
672     JNIEnv *vm_env = get_vm_env();
673     jfieldID id = vm_env->GetStaticFieldID(cls, name, signature);
674
675     reportException();
676
677     return vm_env->GetStaticObjectField(cls, id);
678 }
679
680 #define DEFINE_GET_STATIC_FIELD(jtype, Type, signature)                 \
681     jtype JCCEnv::getStatic##Type##Field(jclass cls,                    \
682                                          const char *name) const        \
683     {                                                                   \
684         JNIEnv *vm_env = get_vm_env();                                  \
685         jfieldID id = vm_env->GetStaticFieldID(cls, name, #signature);  \
686         reportException();                                              \
687         return vm_env->GetStatic##Type##Field(cls, id);                 \
688     }
689
690 DEFINE_GET_STATIC_FIELD(jboolean, Boolean, Z)
691 DEFINE_GET_STATIC_FIELD(jbyte, Byte, B)
692 DEFINE_GET_STATIC_FIELD(jchar, Char, C)
693 DEFINE_GET_STATIC_FIELD(jdouble, Double, D)
694 DEFINE_GET_STATIC_FIELD(jfloat, Float, F)
695 DEFINE_GET_STATIC_FIELD(jint, Int, I)
696 DEFINE_GET_STATIC_FIELD(jlong, Long, J)
697 DEFINE_GET_STATIC_FIELD(jshort, Short, S)
698
699 #define DEFINE_GET_FIELD(jtype, Type)                                   \
700     jtype JCCEnv::get##Type##Field(jobject obj, jfieldID id) const      \
701     {                                                                   \
702         jtype value = get_vm_env()->Get##Type##Field(obj, id);          \
703         reportException();                                              \
704         return value;                                                   \
705     }
706
707 DEFINE_GET_FIELD(jobject, Object)
708 DEFINE_GET_FIELD(jboolean, Boolean)
709 DEFINE_GET_FIELD(jbyte, Byte)
710 DEFINE_GET_FIELD(jchar, Char)
711 DEFINE_GET_FIELD(jdouble, Double)
712 DEFINE_GET_FIELD(jfloat, Float)
713 DEFINE_GET_FIELD(jint, Int)
714 DEFINE_GET_FIELD(jlong, Long)
715 DEFINE_GET_FIELD(jshort, Short)
716
717 #define DEFINE_SET_FIELD(jtype, Type)                                   \
718     void JCCEnv::set##Type##Field(jobject obj, jfieldID id,             \
719                                   jtype value) const                    \
720     {                                                                   \
721         get_vm_env()->Set##Type##Field(obj, id, value);                 \
722         reportException();                                              \
723     }
724
725 DEFINE_SET_FIELD(jobject, Object)
726 DEFINE_SET_FIELD(jboolean, Boolean)
727 DEFINE_SET_FIELD(jbyte, Byte)
728 DEFINE_SET_FIELD(jchar, Char)
729 DEFINE_SET_FIELD(jdouble, Double)
730 DEFINE_SET_FIELD(jfloat, Float)
731 DEFINE_SET_FIELD(jint, Int)
732 DEFINE_SET_FIELD(jlong, Long)
733 DEFINE_SET_FIELD(jshort, Short)
734
735 void JCCEnv::setClassPath(const char *classPath)
736 {
737     JNIEnv *vm_env = get_vm_env();
738     jclass _ucl = (jclass) vm_env->FindClass("java/net/URLClassLoader");
739     jclass _fil = (jclass) vm_env->FindClass("java/io/File");
740     jmethodID mid = vm_env->GetStaticMethodID(_ucl, "getSystemClassLoader",
741                                               "()Ljava/lang/ClassLoader;");
742     jobject classLoader = vm_env->CallStaticObjectMethod(_ucl, mid);
743     jmethodID mf = vm_env->GetMethodID(_fil, "<init>", "(Ljava/lang/String;)V");
744     jmethodID mu = vm_env->GetMethodID(_fil, "toURL", "()Ljava/net/URL;");
745     jmethodID ma = vm_env->GetMethodID(_ucl, "addURL", "(Ljava/net/URL;)V");
746 #if defined(_MSC_VER) || defined(__WIN32)
747     char *pathsep = ";";
748     char *path = _strdup(classPath);
749 #else
750     char *pathsep = ":";
751     char *path = strdup(classPath);
752 #endif
753
754     for (char *cp = strtok(path, pathsep);
755          cp != NULL;
756          cp = strtok(NULL, pathsep)) {
757         jstring string = vm_env->NewStringUTF(cp);
758         jobject file = vm_env->NewObject(_fil, mf, string);
759         jobject url = vm_env->CallObjectMethod(file, mu);
760
761         vm_env->CallVoidMethod(classLoader, ma, url);
762     }
763     free(path);
764 }
765
766 char *JCCEnv::getClassPath()
767 {
768     JNIEnv *vm_env = get_vm_env();
769     jclass _ucl = (jclass) vm_env->FindClass("java/net/URLClassLoader");
770     jclass _url = (jclass) vm_env->FindClass("java/net/URL");
771     jmethodID mid = vm_env->GetStaticMethodID(_ucl, "getSystemClassLoader",
772                                               "()Ljava/lang/ClassLoader;");
773     jobject classLoader = vm_env->CallStaticObjectMethod(_ucl, mid);
774     jmethodID gu = vm_env->GetMethodID(_ucl, "getURLs", "()[Ljava/net/URL;");
775     jmethodID gp = vm_env->GetMethodID(_url, "getPath", "()Ljava/lang/String;");
776 #if defined(_MSC_VER) || defined(__WIN32)
777     char *pathsep = ";";
778 #else
779     char *pathsep = ":";
780 #endif
781     jobjectArray array = (jobjectArray)
782         vm_env->CallObjectMethod(classLoader, gu);
783     int count = array ? vm_env->GetArrayLength(array) : 0;
784     int first = 1, total = 0;
785     char *classpath = NULL;
786     
787     for (int i = 0; i < count; i++) {
788         jobject url = vm_env->GetObjectArrayElement(array, i);
789         jstring path = (jstring) vm_env->CallObjectMethod(url, gp);
790         const char *chars = vm_env->GetStringUTFChars(path, NULL);
791         int size = vm_env->GetStringUTFLength(path);
792
793         total += size + 1;
794         if (classpath == NULL)
795             classpath = (char *) calloc(total, 1);
796         else
797             classpath = (char *) realloc(classpath, total);
798         if (classpath == NULL)
799             return NULL;
800
801         if (first)
802             first = 0;
803         else
804             strcat(classpath, pathsep);
805
806         strcat(classpath, chars);
807     }
808
809     return classpath;
810 }
811
812 jstring JCCEnv::fromUTF(const char *bytes) const
813 {
814     jstring str = get_vm_env()->NewStringUTF(bytes);
815
816     reportException();
817
818     return str;
819 }
820
821 char *JCCEnv::toUTF(jstring str) const
822 {
823     JNIEnv *vm_env = get_vm_env();
824     int len = vm_env->GetStringUTFLength(str);
825     char *bytes = new char[len + 1];
826     jboolean isCopy = 0;
827     const char *utf = vm_env->GetStringUTFChars(str, &isCopy);
828
829     if (!bytes)
830         return NULL;
831
832     memcpy(bytes, utf, len);
833     bytes[len] = '\0';
834
835     vm_env->ReleaseStringUTFChars(str, utf);
836
837     return bytes;
838 }
839
840 char *JCCEnv::toString(jobject obj) const
841 {
842     try {
843         return obj
844             ? toUTF((jstring) callObjectMethod(obj, _mids[mid_obj_toString]))
845             : NULL;
846     } catch (int e) {
847         switch (e) {
848           case _EXC_PYTHON:
849             return NULL;
850           case _EXC_JAVA: {
851               JNIEnv *vm_env = get_vm_env();
852
853               vm_env->ExceptionDescribe();
854               vm_env->ExceptionClear();
855
856               return NULL;
857           }
858           default:
859             throw;
860         }
861     }
862 }
863
864 char *JCCEnv::getClassName(jobject obj) const
865 {
866     return obj
867         ? toString(callObjectMethod(obj, _mids[mid_obj_getClass]))
868         : NULL;
869 }
870
871 #ifdef PYTHON
872
873 jstring JCCEnv::fromPyString(PyObject *object) const
874 {
875     if (object == Py_None)
876         return NULL;
877
878     if (PyUnicode_Check(object))
879     {
880         if (sizeof(Py_UNICODE) == sizeof(jchar))
881         {
882             jchar *buf = (jchar *) PyUnicode_AS_UNICODE(object);
883             jsize len = (jsize) PyUnicode_GET_SIZE(object);
884
885             return get_vm_env()->NewString(buf, len);
886         }
887         else
888         {
889             jsize len = PyUnicode_GET_SIZE(object);
890             Py_UNICODE *pchars = PyUnicode_AS_UNICODE(object);
891             jchar *jchars = new jchar[len];
892             jstring str;
893
894             for (int i = 0; i < len; i++)
895                 jchars[i] = (jchar) pchars[i];
896
897             str = get_vm_env()->NewString(jchars, len);
898             delete jchars;
899
900             return str;
901         }
902     }
903     else if (PyString_Check(object))
904         return fromUTF(PyString_AS_STRING(object));
905     else
906     {
907         PyObject *tuple = Py_BuildValue("(sO)", "expected a string", object);
908
909         PyErr_SetObject(PyExc_TypeError, tuple);
910         Py_DECREF(tuple);
911
912         return NULL;
913     }
914 }
915
916 PyObject *JCCEnv::fromJString(jstring js, int delete_local_ref) const
917 {
918     if (!js)
919         Py_RETURN_NONE;
920
921     JNIEnv *vm_env = get_vm_env();
922     PyObject *string;
923
924     if (sizeof(Py_UNICODE) == sizeof(jchar))
925     {
926         jboolean isCopy;
927         const jchar *buf = vm_env->GetStringChars(js, &isCopy);
928         jsize len = vm_env->GetStringLength(js);
929
930         string = PyUnicode_FromUnicode((const Py_UNICODE *) buf, len);
931         vm_env->ReleaseStringChars(js, buf);
932     }
933     else
934     {
935         jsize len = vm_env->GetStringLength(js);
936
937         string = PyUnicode_FromUnicode(NULL, len);
938         if (string)
939         {
940             jboolean isCopy;
941             const jchar *jchars = vm_env->GetStringChars(js, &isCopy);
942             Py_UNICODE *pchars = PyUnicode_AS_UNICODE(string);
943
944             for (int i = 0; i < len; i++)
945                 pchars[i] = (Py_UNICODE) jchars[i];
946         
947             vm_env->ReleaseStringChars(js, jchars);
948         }
949     }
950
951     if (delete_local_ref)
952         vm_env->DeleteLocalRef((jobject) js);
953
954     return string;
955 }
956
957
958 /* may be called from finalizer thread which has no vm_env thread local */
959 void JCCEnv::finalizeObject(JNIEnv *jenv, PyObject *obj)
960 {
961     PythonGIL gil;
962
963     set_vm_env(jenv);
964     Py_DECREF(obj);
965 }
966
967 #endif /* PYTHON */