PyLucene 3.4.0-1 import
[pylucene.git] / jcc / jcc / sources / jcc.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 <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <jni.h>
19
20 #ifdef linux
21 #include <dlfcn.h>
22 #endif
23
24 #include <Python.h>
25 #include "structmember.h"
26
27 #include "JObject.h"
28 #include "JCCEnv.h"
29 #include "macros.h"
30
31 _DLL_EXPORT JCCEnv *env;
32
33
34 /* JCCEnv */
35
36 class t_jccenv {
37 public:
38     PyObject_HEAD
39     JCCEnv *env;
40 };
41     
42 static void t_jccenv_dealloc(t_jccenv *self);
43 static PyObject *t_jccenv_attachCurrentThread(PyObject *self, PyObject *args);
44 static PyObject *t_jccenv_detachCurrentThread(PyObject *self);
45 static PyObject *t_jccenv_isCurrentThreadAttached(PyObject *self);
46 static PyObject *t_jccenv_strhash(PyObject *self, PyObject *arg);
47 static PyObject *t_jccenv__dumpRefs(PyObject *self,
48                                     PyObject *args, PyObject *kwds);
49 static PyObject *t_jccenv__addClassPath(PyObject *self, PyObject *args);
50
51 static PyObject *t_jccenv__get_jni_version(PyObject *self, void *data);
52 static PyObject *t_jccenv__get_java_version(PyObject *self, void *data);
53 static PyObject *t_jccenv__get_classpath(PyObject *self, void *data);
54
55 static PyGetSetDef t_jccenv_properties[] = {
56     { "jni_version", (getter) t_jccenv__get_jni_version, NULL, NULL, NULL },
57     { "java_version", (getter) t_jccenv__get_java_version, NULL, NULL, NULL },
58     { "classpath", (getter) t_jccenv__get_classpath, NULL, NULL, NULL },
59     { NULL, NULL, NULL, NULL, NULL }
60 };
61
62 static PyMemberDef t_jccenv_members[] = {
63     { NULL, 0, 0, 0, NULL }
64 };
65
66 static PyMethodDef t_jccenv_methods[] = {
67     { "attachCurrentThread", (PyCFunction) t_jccenv_attachCurrentThread,
68       METH_VARARGS, NULL },
69     { "detachCurrentThread", (PyCFunction) t_jccenv_detachCurrentThread,
70       METH_NOARGS, NULL },
71     { "isCurrentThreadAttached", (PyCFunction) t_jccenv_isCurrentThreadAttached,
72       METH_NOARGS, NULL },
73     { "strhash", (PyCFunction) t_jccenv_strhash,
74       METH_O, NULL },
75     { "_dumpRefs", (PyCFunction) t_jccenv__dumpRefs,
76       METH_VARARGS | METH_KEYWORDS, NULL },
77     { "_addClassPath", (PyCFunction) t_jccenv__addClassPath,
78       METH_VARARGS, NULL },
79     { NULL, NULL, 0, NULL }
80 };
81
82 PyTypeObject PY_TYPE(JCCEnv) = {
83     PyObject_HEAD_INIT(NULL)
84     0,                                   /* ob_size */
85     "jcc.JCCEnv",                        /* tp_name */
86     sizeof(t_jccenv),                    /* tp_basicsize */
87     0,                                   /* tp_itemsize */
88     (destructor)t_jccenv_dealloc,        /* tp_dealloc */
89     0,                                   /* tp_print */
90     0,                                   /* tp_getattr */
91     0,                                   /* tp_setattr */
92     0,                                   /* tp_compare */
93     0,                                   /* tp_repr */
94     0,                                   /* tp_as_number */
95     0,                                   /* tp_as_sequence */
96     0,                                   /* tp_as_mapping */
97     0,                                   /* tp_hash  */
98     0,                                   /* tp_call */
99     0,                                   /* tp_str */
100     0,                                   /* tp_getattro */
101     0,                                   /* tp_setattro */
102     0,                                   /* tp_as_buffer */
103     Py_TPFLAGS_DEFAULT,                  /* tp_flags */
104     "JCCEnv",                            /* tp_doc */
105     0,                                   /* tp_traverse */
106     0,                                   /* tp_clear */
107     0,                                   /* tp_richcompare */
108     0,                                   /* tp_weaklistoffset */
109     0,                                   /* tp_iter */
110     0,                                   /* tp_iternext */
111     t_jccenv_methods,                    /* tp_methods */
112     t_jccenv_members,                    /* tp_members */
113     t_jccenv_properties,                 /* tp_getset */
114     0,                                   /* tp_base */
115     0,                                   /* tp_dict */
116     0,                                   /* tp_descr_get */
117     0,                                   /* tp_descr_set */
118     0,                                   /* tp_dictoffset */
119     0,                                   /* tp_init */
120     0,                                   /* tp_alloc */
121     0,                                   /* tp_new */
122 };
123
124 static void t_jccenv_dealloc(t_jccenv *self)
125 {
126     self->ob_type->tp_free((PyObject *) self);
127 }
128
129 static void add_option(char *name, char *value, JavaVMOption *option)
130 {
131     char *buf = new char[strlen(name) + strlen(value) + 1];
132
133     sprintf(buf, "%s%s", name, value);
134     option->optionString = buf;
135 }
136
137 #ifdef _jcc_lib
138 static void add_paths(char *name, char *p0, char *p1, JavaVMOption *option)
139 {
140 #if defined(_MSC_VER) || defined(__WIN32)
141     char pathsep = ';';
142 #else
143     char pathsep = ':';
144 #endif
145     char *buf = new char[strlen(name) + strlen(p0) + strlen(p1) + 4];
146
147     sprintf(buf, "%s%s%c%s", name, p0, pathsep, p1);
148     option->optionString = buf;
149 }
150 #endif
151
152
153 static PyObject *t_jccenv_attachCurrentThread(PyObject *self, PyObject *args)
154 {
155     char *name = NULL;
156     int asDaemon = 0, result;
157
158     if (!PyArg_ParseTuple(args, "|si", &name, &asDaemon))
159         return NULL;
160
161     result = env->attachCurrentThread(name, asDaemon);
162         
163     return PyInt_FromLong(result);
164 }
165
166 static PyObject *t_jccenv_detachCurrentThread(PyObject *self)
167 {
168     int result = env->vm->DetachCurrentThread();
169
170     env->set_vm_env(NULL);
171
172     return PyInt_FromLong(result);
173 }
174
175 static PyObject *t_jccenv_isCurrentThreadAttached(PyObject *self)
176 {
177     if (env->get_vm_env() != NULL)
178         Py_RETURN_TRUE;
179
180     Py_RETURN_FALSE;
181 }
182
183 static PyObject *t_jccenv_strhash(PyObject *self, PyObject *arg)
184 {
185     int hash = PyObject_Hash(arg);
186     char buffer[10];
187
188     sprintf(buffer, "%08x", (unsigned int) hash);
189     return PyString_FromStringAndSize(buffer, 8);
190 }
191
192 static PyObject *t_jccenv__dumpRefs(PyObject *self,
193                                     PyObject *args, PyObject *kwds)
194 {
195     static char *kwnames[] = {
196         "classes", "values", NULL
197     };
198     int classes = 0, values = 0;
199     PyObject *result;
200
201     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwnames,
202                                      &classes, &values))
203         return NULL;
204
205     if (classes)
206         result = PyDict_New();
207     else
208         result = PyList_New(env->refs.size());
209
210     int count = 0;
211
212     for (std::multimap<int, countedRef>::iterator iter = env->refs.begin();
213          iter != env->refs.end();
214          iter++) {
215         if (classes)  // return dict of { class name: instance count }
216         {
217             char *name = env->getClassName(iter->second.global);
218             PyObject *key = PyString_FromString(name);
219             PyObject *value = PyDict_GetItem(result, key);
220
221             if (value == NULL)
222                 value = PyInt_FromLong(1);
223             else
224                 value = PyInt_FromLong(PyInt_AS_LONG(value) + 1);
225
226             PyDict_SetItem(result, key, value);
227             Py_DECREF(key);
228             Py_DECREF(value);
229
230             delete name;
231         }
232         else if (values)  // return list of (value string, ref count)
233         {
234             char *str = env->toString(iter->second.global);
235             PyObject *key = PyString_FromString(str);
236             PyObject *value = PyInt_FromLong(iter->second.count);
237
238 #if PY_VERSION_HEX < 0x02040000
239             PyList_SET_ITEM(result, count++, Py_BuildValue("(OO)", key, value));
240 #else
241             PyList_SET_ITEM(result, count++, PyTuple_Pack(2, key, value));
242 #endif
243             Py_DECREF(key);
244             Py_DECREF(value);
245
246             delete str;
247         }
248         else  // return list of (id hash code, ref count)
249         {
250             PyObject *key = PyInt_FromLong(iter->first);
251             PyObject *value = PyInt_FromLong(iter->second.count);
252
253 #if PY_VERSION_HEX < 0x02040000
254             PyList_SET_ITEM(result, count++, Py_BuildValue("(OO)", key, value));
255 #else
256             PyList_SET_ITEM(result, count++, PyTuple_Pack(2, key, value));
257 #endif
258             Py_DECREF(key);
259             Py_DECREF(value);
260         }
261     }
262
263     return result;
264 }
265
266 static PyObject *t_jccenv__addClassPath(PyObject *self, PyObject *args)
267 {
268     const char *classpath;
269
270     if (!PyArg_ParseTuple(args, "s", &classpath))
271         return NULL;
272
273     env->setClassPath(classpath);
274
275     Py_RETURN_NONE;
276 }
277
278 static PyObject *t_jccenv__get_jni_version(PyObject *self, void *data)
279 {
280     return PyInt_FromLong(env->getJNIVersion());
281 }
282
283 static PyObject *t_jccenv__get_java_version(PyObject *self, void *data)
284 {
285     return env->fromJString(env->getJavaVersion(), 1);
286 }
287
288 static PyObject *t_jccenv__get_classpath(PyObject *self, void *data)
289 {
290     char *classpath = env->getClassPath();
291
292     if (classpath)
293     {
294         PyObject *result = PyString_FromString(classpath);
295
296         free(classpath);
297         return result;
298     }
299
300     Py_RETURN_NONE;
301 }
302
303 _DLL_EXPORT PyObject *getVMEnv(PyObject *self)
304 {
305     if (env->vm != NULL)
306     {
307         t_jccenv *jccenv = (t_jccenv *) PY_TYPE(JCCEnv).tp_alloc(&PY_TYPE(JCCEnv), 0);
308         jccenv->env = env;
309
310         return (PyObject *) jccenv;
311     }
312
313     Py_RETURN_NONE;
314 }
315
316 #ifdef _jcc_lib
317 static void registerNatives(JNIEnv *vm_env);
318 #endif
319
320 _DLL_EXPORT PyObject *initJCC(PyObject *module)
321 {
322     static int _once_only = 1;
323 #if defined(_MSC_VER) || defined(__WIN32)
324 #define verstring(n) #n
325     PyObject *ver = PyString_FromString(verstring(JCC_VER));
326 #else
327     PyObject *ver = PyString_FromString(JCC_VER);
328 #endif
329     PyObject_SetAttrString(module, "JCC_VERSION", ver); Py_DECREF(ver);
330
331     if (_once_only)
332     {
333         PyEval_InitThreads();
334         INSTALL_TYPE(JCCEnv, module);
335
336         if (env == NULL)
337             env = new JCCEnv(NULL, NULL);
338
339         _once_only = 0;
340         Py_RETURN_TRUE;
341     }
342
343     Py_RETURN_FALSE;
344 }
345
346 _DLL_EXPORT PyObject *initVM(PyObject *self, PyObject *args, PyObject *kwds)
347 {
348     static char *kwnames[] = {
349         "classpath", "initialheap", "maxheap", "maxstack",
350         "vmargs", NULL
351     };
352     char *classpath = NULL;
353     char *initialheap = NULL, *maxheap = NULL, *maxstack = NULL;
354     char *vmargs = NULL;
355
356     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzzzz", kwnames,
357                                      &classpath,
358                                      &initialheap, &maxheap, &maxstack,
359                                      &vmargs))
360         return NULL;
361
362     if (env->vm)
363     {
364         PyObject *module_cp = NULL;
365
366         if (initialheap || maxheap || maxstack || vmargs)
367         {
368             PyErr_SetString(PyExc_ValueError,
369                             "JVM is already running, options are ineffective");
370             return NULL;
371         }
372
373         if (classpath == NULL && self != NULL)
374         {
375             module_cp = PyObject_GetAttrString(self, "CLASSPATH");
376             if (module_cp != NULL)
377                 classpath = PyString_AsString(module_cp);
378         }
379
380         if (classpath && classpath[0])
381             env->setClassPath(classpath);
382
383         Py_XDECREF(module_cp);
384
385         return getVMEnv(self);
386     }
387     else
388     {
389         JavaVMInitArgs vm_args;
390         JavaVMOption vm_options[32];
391         JNIEnv *vm_env;
392         JavaVM *vm;
393         unsigned int nOptions = 0;
394         PyObject *module_cp = NULL;
395
396         vm_args.version = JNI_VERSION_1_4;
397         JNI_GetDefaultJavaVMInitArgs(&vm_args);
398
399         if (classpath == NULL && self != NULL)
400         {
401             module_cp = PyObject_GetAttrString(self, "CLASSPATH");
402             if (module_cp != NULL)
403                 classpath = PyString_AsString(module_cp);
404         }
405
406 #ifdef _jcc_lib
407         PyObject *jcc = PyImport_ImportModule("jcc");
408         PyObject *cp = PyObject_GetAttrString(jcc, "CLASSPATH");
409
410         if (classpath)
411             add_paths("-Djava.class.path=", PyString_AsString(cp), classpath,
412                       &vm_options[nOptions++]);
413         else
414             add_option("-Djava.class.path=", PyString_AsString(cp),
415                        &vm_options[nOptions++]);
416             
417         Py_DECREF(cp);
418         Py_DECREF(jcc);
419 #else
420         if (classpath)
421             add_option("-Djava.class.path=", classpath,
422                        &vm_options[nOptions++]);
423 #endif
424
425         Py_XDECREF(module_cp);
426
427         if (initialheap)
428             add_option("-Xms", initialheap, &vm_options[nOptions++]);
429         if (maxheap)
430             add_option("-Xmx", maxheap, &vm_options[nOptions++]);
431         if (maxstack)
432             add_option("-Xss", maxstack, &vm_options[nOptions++]);
433
434         if (vmargs)
435         {
436 #ifdef _MSC_VER
437             char *buf = _strdup(vmargs);
438 #else
439             char *buf = strdup(vmargs);
440 #endif
441             char *sep = ",";
442             char *option;
443
444             for (option = strtok(buf, sep); option; option = strtok(NULL, sep))
445             {
446                 if (nOptions < sizeof(vm_options) / sizeof(JavaVMOption))
447                     add_option("", option, &vm_options[nOptions++]);
448                 else
449                 {
450                     free(buf);
451                     for (unsigned int i = 0; i < nOptions; i++)
452                         delete vm_options[i].optionString;
453                     PyErr_Format(PyExc_ValueError, "Too many options (> %d)",
454                                  nOptions);
455                     return NULL;
456                 }
457             }
458             free(buf);
459         }
460
461         //vm_options[nOptions++].optionString = "-verbose:gc";
462         //vm_options[nOptions++].optionString = "-Xcheck:jni";
463
464         vm_args.nOptions = nOptions;
465         vm_args.ignoreUnrecognized = JNI_FALSE;
466         vm_args.options = vm_options;
467
468         if (JNI_CreateJavaVM(&vm, (void **) &vm_env, &vm_args) < 0)
469         {
470             for (unsigned int i = 0; i < nOptions; i++)
471                 delete vm_options[i].optionString;
472
473             PyErr_Format(PyExc_ValueError,
474                          "An error occurred while creating Java VM");
475             return NULL;
476         }
477
478         env->set_vm(vm, vm_env);
479
480         for (unsigned int i = 0; i < nOptions; i++)
481             delete vm_options[i].optionString;
482
483         t_jccenv *jccenv = (t_jccenv *) PY_TYPE(JCCEnv).tp_alloc(&PY_TYPE(JCCEnv), 0);
484         jccenv->env = env;
485
486 #ifdef _jcc_lib
487         registerNatives(vm_env);
488 #endif
489
490         return (PyObject *) jccenv;
491     }
492 }
493
494 #ifdef _jcc_lib
495
496 static void raise_error(JNIEnv *vm_env, const char *message)
497 {
498     jclass cls = vm_env->FindClass("org/apache/jcc/PythonException");
499     vm_env->ThrowNew(cls, message);
500 }
501
502 static void _PythonVM_init(JNIEnv *vm_env, jobject self,
503                            jstring programName, jobjectArray args)
504 {
505     const char *str = vm_env->GetStringUTFChars(programName, JNI_FALSE);
506 #ifdef linux
507     char buf[32];
508
509     // load python runtime for other .so modules to link (such as _time.so)
510     sprintf(buf, "libpython%d.%d.so", PY_MAJOR_VERSION, PY_MINOR_VERSION);
511     dlopen(buf, RTLD_NOW | RTLD_GLOBAL);
512 #endif
513
514     Py_SetProgramName((char *) str);
515
516     PyEval_InitThreads();
517     Py_Initialize();
518
519     if (args)
520     {
521         int argc = vm_env->GetArrayLength(args);
522         char **argv = (char **) calloc(argc + 1, sizeof(char *));
523
524         argv[0] = (char *) str;
525         for (int i = 0; i < argc; i++) {
526             jstring arg = (jstring) vm_env->GetObjectArrayElement(args, i);
527             argv[i + 1] = (char *) vm_env->GetStringUTFChars(arg, JNI_FALSE);
528         }
529
530         PySys_SetArgv(argc + 1, argv);
531
532         for (int i = 0; i < argc; i++) {
533             jstring arg = (jstring) vm_env->GetObjectArrayElement(args, i);
534             vm_env->ReleaseStringUTFChars(arg, argv[i + 1]);
535         }
536         free(argv);
537     }
538     else
539         PySys_SetArgv(1, (char **) &str);
540
541     vm_env->ReleaseStringUTFChars(programName, str);
542     PyEval_ReleaseLock();
543 }
544
545 static jobject _PythonVM_instantiate(JNIEnv *vm_env, jobject self,
546                                      jstring moduleName, jstring className)
547 {
548     PythonGIL gil(vm_env);
549
550     const char *modStr = vm_env->GetStringUTFChars(moduleName, JNI_FALSE);
551     PyObject *module =
552         PyImport_ImportModule((char *) modStr);  // python 2.4 cast
553
554     vm_env->ReleaseStringUTFChars(moduleName, modStr);
555
556     if (!module)
557     {
558         raise_error(vm_env, "import failed");
559         return NULL;
560     }
561
562     const char *clsStr = vm_env->GetStringUTFChars(className, JNI_FALSE);
563     PyObject *cls =
564         PyObject_GetAttrString(module, (char *) clsStr); // python 2.4 cast
565     PyObject *obj;
566     jobject jobj;
567
568     vm_env->ReleaseStringUTFChars(className, clsStr);
569     Py_DECREF(module);
570
571     if (!cls)
572     {
573         raise_error(vm_env, "class not found");
574         return NULL;
575     }
576
577     obj = PyObject_CallFunctionObjArgs(cls, NULL);
578     Py_DECREF(cls);
579
580     if (!obj)
581     {
582         raise_error(vm_env, "instantiation failed");
583         return NULL;
584     }
585
586     PyObject *cObj = PyObject_GetAttrString(obj, "_jobject");
587
588     if (!cObj)
589     {
590         raise_error(vm_env, "instance does not proxy a java object");
591         Py_DECREF(obj);
592
593         return NULL;
594     }
595
596     jobj = (jobject) PyCObject_AsVoidPtr(cObj);
597     Py_DECREF(cObj);
598
599     jobj = vm_env->NewLocalRef(jobj);
600     Py_DECREF(obj);
601
602     return jobj;
603 }
604
605 extern "C" {
606
607     JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
608     {
609         JNIEnv *vm_env;
610
611         if (!vm->GetEnv((void **) &vm_env, JNI_VERSION_1_4))
612             env = new JCCEnv(vm, vm_env);
613
614         registerNatives(vm_env);
615
616         return JNI_VERSION_1_4;
617     }
618
619     JNIEXPORT void JNICALL Java_org_apache_jcc_PythonVM_init(JNIEnv *vm_env, jobject self, jstring programName, jobjectArray args)
620     {
621         return _PythonVM_init(vm_env, self, programName, args);
622     }
623
624     JNIEXPORT jobject JNICALL Java_org_apache_jcc_PythonVM_instantiate(JNIEnv *vm_env, jobject self, jstring moduleName, jstring className)
625     {
626         return _PythonVM_instantiate(vm_env, self, moduleName, className);
627     }
628
629     JNIEXPORT jint JNICALL Java_org_apache_jcc_PythonVM_acquireThreadState(JNIEnv *vm_env)
630     {
631         PyGILState_STATE state = PyGILState_Ensure();
632         PyThreadState *tstate = PyGILState_GetThisThreadState();
633         int result = -1;
634
635         if (tstate != NULL && tstate->gilstate_counter >= 1)
636             result = ++tstate->gilstate_counter;
637
638         PyGILState_Release(state);
639         return result;
640     }
641
642     JNIEXPORT jint JNICALL Java_org_apache_jcc_PythonVM_releaseThreadState(JNIEnv *vm_env)
643     {
644         PyGILState_STATE state = PyGILState_Ensure();
645         PyThreadState *tstate = PyGILState_GetThisThreadState();
646         int result = -1;
647
648         if (tstate != NULL && tstate->gilstate_counter >= 1)
649             result = --tstate->gilstate_counter;
650
651         PyGILState_Release(state);
652         return result;
653     }
654 };
655
656 static void JNICALL _PythonException_getErrorInfo(JNIEnv *vm_env, jobject self)
657 {
658     PythonGIL gil(vm_env);
659
660     if (!PyErr_Occurred())
661         return;
662
663     PyObject *type, *value, *tb, *errorName;
664     jclass jcls = vm_env->GetObjectClass(self);
665
666     PyErr_Fetch(&type, &value, &tb);
667
668     errorName = PyObject_GetAttrString(type, "__name__");
669     if (errorName != NULL)
670     {
671         jfieldID fid =
672             vm_env->GetFieldID(jcls, "errorName", "Ljava/lang/String;");
673         jstring str = env->fromPyString(errorName);
674
675         vm_env->SetObjectField(self, fid, str);
676         vm_env->DeleteLocalRef(str);
677         Py_DECREF(errorName);
678     }
679
680     if (value != NULL)
681     {
682         PyObject *message = PyObject_Str(value);
683
684         if (message != NULL)
685         {
686             jfieldID fid =
687                 vm_env->GetFieldID(jcls, "message", "Ljava/lang/String;");
688             jstring str = env->fromPyString(message);
689
690             vm_env->SetObjectField(self, fid, str);
691             vm_env->DeleteLocalRef(str);
692             Py_DECREF(message);
693         }
694     }
695
696     PyObject *module = NULL, *cls = NULL, *stringIO = NULL, *result = NULL;
697     PyObject *_stderr = PySys_GetObject("stderr");
698     if (!_stderr)
699         goto err;
700
701     module = PyImport_ImportModule("cStringIO");
702     if (!module)
703         goto err;
704
705     cls = PyObject_GetAttrString(module, "StringIO");
706     Py_DECREF(module);
707     if (!cls)
708         goto err;
709
710     stringIO = PyObject_CallObject(cls, NULL);
711     Py_DECREF(cls);
712     if (!stringIO)
713         goto err;
714
715     Py_INCREF(_stderr);
716     PySys_SetObject("stderr", stringIO);
717
718     PyErr_Restore(type, value, tb);
719     PyErr_Print();
720
721     result = PyObject_CallMethod(stringIO, "getvalue", NULL);
722     Py_DECREF(stringIO);
723
724     if (result != NULL)
725     {
726         jfieldID fid =
727             vm_env->GetFieldID(jcls, "traceback", "Ljava/lang/String;");
728         jstring str = env->fromPyString(result);
729
730         vm_env->SetObjectField(self, fid, str);
731         vm_env->DeleteLocalRef(str);
732         Py_DECREF(result);
733     }
734
735     PySys_SetObject("stderr", _stderr);
736     Py_DECREF(_stderr);
737
738     return;
739
740   err:
741     PyErr_Restore(type, value, tb);
742 }
743
744 static void JNICALL _PythonException_clear(JNIEnv *vm_env, jobject self)
745 {
746     PythonGIL gil(vm_env);
747     PyErr_Clear();
748 }
749
750 static void registerNatives(JNIEnv *vm_env)
751 {
752     jclass cls = vm_env->FindClass("org/apache/jcc/PythonException");
753     JNINativeMethod methods[] = {
754         { "getErrorInfo", "()V", (void *) _PythonException_getErrorInfo },
755         { "clear", "()V", (void *) _PythonException_clear },
756     };
757
758     vm_env->RegisterNatives(cls, methods, 2);
759 }
760
761 #endif /* _jcc_lib */