2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 /***************************************************************************
19 * Description: In process JNI worker *
20 * Author: Gal Shachor <shachor@il.ibm.com> *
22 * Version: $Revision: 750428 $ *
23 ***************************************************************************/
25 #if !defined(WIN32) && !defined(NETWARE) && !defined(AS400)
32 #include "jk_jni_worker.h"
35 #if !defined(JNI_VERSION_1_6)
36 #if defined LINUX && defined APACHE2_SIGHACK
39 #include <bits/signum.h>
43 #ifdef __NOVELL_LIBC__
51 #ifndef JNI_VERSION_1_1
52 #define JNI_VERSION_1_1 0x00010001
55 /* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY.
56 * The below define is a lie since we are really doing RTLD_LAZY since the
57 * system doesn't support RTLD_NOW.
67 #define null_check(e) if ((e) == 0) return JK_FALSE
69 jint(JNICALL * jni_get_default_java_vm_init_args) (void *) = NULL;
70 jint(JNICALL * jni_create_java_vm) (JavaVM **, JNIEnv **, void *) = NULL;
72 jint(JNICALL * jni_get_created_java_vms) (JavaVM **, long, long *) = NULL;
74 jint(JNICALL * jni_get_created_java_vms) (JavaVM **, int, int *) = NULL;
77 #define TC33_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint")
78 #define TC32_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/service/JNIEndpoint")
80 static jk_worker_t *the_singleton_jni_worker = NULL;
89 jk_pool_atom_t buf[TINY_POOL_SIZE];
97 * [V] JNIEnv used for boostraping from validate -> init w/o an attach
102 * Web Server to Java bridge, instance and class.
104 jobject jk_java_bridge_object;
105 jclass jk_java_bridge_class;
108 * Java methods ids, to jump into the JVM
110 jmethodID jk_startup_method;
111 jmethodID jk_service_method;
112 jmethodID jk_shutdown_method;
115 * Command line for tomcat startup
117 char *tomcat_cmd_line;
120 * Bridge Type, Tomcat 32/33/40/41/5
122 unsigned bridge_type;
127 char *tomcat_classpath;
130 * Full path to the jni javai/jvm dll
135 * Initial Java heap size
145 * Java system properties
149 #ifdef JNI_VERSION_1_2
151 * Java 2 initialization options (-X... , -verbose etc.)
156 * Java 2 lax/strict option checking (bool)
162 * stdout and stderr file names for Java
170 typedef struct jni_worker jni_worker_t;
176 jni_worker_t *worker;
178 jk_endpoint_t endpoint;
180 typedef struct jni_endpoint jni_endpoint_t;
183 static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l);
185 static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
187 static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
189 #ifdef JNI_VERSION_1_2
190 static int detect_jvm_version(jk_logger_t *l);
192 static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
196 static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
198 static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
200 static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l);
202 static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l);
206 Duplicate string and convert it to ASCII on EBDIC based systems
207 Needed for at least AS/400 (before V5R4 ?) and BS2000 but what about other EBDIC systems ?
209 static void *strdup_ascii(jk_pool_t *p, char *s)
212 rc = jk_pool_strdup(p, s);
214 #if defined(AS400) || defined(_OSD_POSIX)
215 jk_xlate_to_ascii(rc, strlen(rc));
221 #if defined LINUX && defined APACHE2_SIGHACK
222 static void linux_signal_hack()
228 pthread_sigmask(SIG_SETMASK, &newM, &old);
230 sigdelset(&old, SIGUSR1);
231 sigdelset(&old, SIGUSR2);
232 sigdelset(&old, SIGUNUSED);
233 sigdelset(&old, SIGRTMIN);
234 sigdelset(&old, SIGRTMIN + 1);
235 sigdelset(&old, SIGRTMIN + 2);
236 pthread_sigmask(SIG_SETMASK, &old, NULL);
239 static void print_signals(sigset_t * sset)
242 for (sig = 1; sig < 20; sig++) {
243 if (sigismember(sset, sig)) {
252 * Return values of service() method for jni worker:
253 * return value is_error reason
254 * JK_FALSE JK_HTTP_SERVER_ERROR Invalid parameters (null values)
255 * Error during attach to the JNI backend
256 * Error during JNI call
257 * JK_TRUE JK_HTTP_OK All other cases
259 static int JK_METHOD service(jk_endpoint_t *e,
261 jk_logger_t *l, int *is_error)
268 if (!e || !e->endpoint_private || !s || !is_error) {
269 JK_LOG_NULL_PARAMS(l);
271 *is_error = JK_HTTP_SERVER_ERROR;
276 p = e->endpoint_private;
278 /* Set returned error to OK */
279 *is_error = JK_HTTP_OK;
283 if (!(p->env = attach_to_jvm(p->worker, l))) {
284 jk_log(l, JK_LOG_EMERG, "Attach failed");
285 *is_error = JK_HTTP_SERVER_ERROR;
289 p->attached = JK_TRUE;
292 /* we are attached now */
295 * When we call the JVM we cannot know what happens
296 * So we can not recover !!!
298 jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat...");
300 rc = (*(p->env))->CallIntMethod(p->env,
301 p->worker->jk_java_bridge_object,
302 p->worker->jk_service_method,
303 /* [V] For some reason gcc likes this pointer -> int -> jlong conversion, */
304 /* but not the direct pointer -> jlong conversion. I hope it's okay. */
308 (jlong) (int)s, (jlong) (int)l
312 /* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */
314 jk_log(l, JK_LOG_DEBUG, "Tomcat returned OK, done");
319 jk_log(l, JK_LOG_ERROR, "Tomcat FAILED!");
320 *is_error = JK_HTTP_SERVER_ERROR;
326 static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
331 if (!e || !*e || !(*e)->endpoint_private) {
332 JK_LOG_NULL_PARAMS(l);
337 p = (*e)->endpoint_private;
340 detach_from_jvm(p->worker, l);
349 static int JK_METHOD validate(jk_worker_t *pThis,
351 jk_worker_env_t *we, jk_logger_t *l)
356 const char *str_config = NULL;
361 if (!pThis || !pThis->worker_private) {
362 JK_LOG_NULL_PARAMS(l);
367 p = pThis->worker_private;
369 if (p->was_verified) {
370 jk_log(l, JK_LOG_DEBUG, "been here before, done");
375 if (jk_get_worker_mx(props, p->name, (unsigned int *)&mem_config)) {
376 p->tomcat_mx = mem_config;
379 if (jk_get_worker_ms(props, p->name, (unsigned int *)&mem_config)) {
380 p->tomcat_ms = mem_config;
383 if (jk_get_worker_classpath(props, p->name, &str_config)) {
384 p->tomcat_classpath = jk_pool_strdup(&p->p, str_config);
387 if (!p->tomcat_classpath) {
388 jk_log(l, JK_LOG_EMERG, "no classpath");
393 if (jk_get_worker_bridge_type(props, p->name, (unsigned int *)&btype)) {
394 p->bridge_type = btype;
397 if (jk_get_worker_jvm_path(props, p->name, &str_config)) {
398 p->jvm_dll_path = jk_pool_strdup(&p->p, str_config);
401 if (!p->jvm_dll_path || !jk_file_exists(p->jvm_dll_path)) {
402 jk_log(l, JK_LOG_EMERG, "no jvm_dll_path");
407 if (jk_get_worker_cmd_line(props, p->name, &str_config)) {
408 p->tomcat_cmd_line = jk_pool_strdup(&p->p, str_config);
411 if (jk_get_worker_stdout(props, p->name, &str_config)) {
412 p->stdout_name = jk_pool_strdup(&p->p, str_config);
415 if (jk_get_worker_stderr(props, p->name, &str_config)) {
416 p->stderr_name = jk_pool_strdup(&p->p, str_config);
419 if (jk_get_worker_sysprops(props, p->name, &str_config)) {
420 p->sysprops = jk_parse_sysprops(&p->p, str_config);
423 #ifdef JNI_VERSION_1_2
424 if (jk_get_worker_str_prop(props, p->name, "java2opts", &str_config)) {
425 /* jk_log(l, JK_LOG_DEBUG, "Got opts: %s", str_config); */
426 p->java2opts = jk_parse_sysprops(&p->p, str_config);
428 if (jk_get_worker_int_prop(props, p->name, "java2lax", &mem_config)) {
429 p->java2lax = mem_config ? JK_TRUE : JK_FALSE;
433 if (jk_get_worker_libpath(props, p->name, &str_config)) {
434 jk_append_libpath(&p->p, str_config);
437 if (!load_jvm_dll(p, l)) {
438 jk_log(l, JK_LOG_EMERG, "can't load jvm dll");
439 /* [V] no detach needed here */
444 if (!open_jvm(p, &env, l)) {
445 jk_log(l, JK_LOG_EMERG, "can't open jvm");
446 /* [V] no detach needed here */
451 if (!get_bridge_object(p, env, l)) {
452 jk_log(l, JK_LOG_EMERG, "can't get bridge object");
453 /* [V] the detach here may segfault on 1.1 JVM... */
454 detach_from_jvm(p, l);
459 if (!get_method_ids(p, env, l)) {
460 jk_log(l, JK_LOG_EMERG, "can't get method ids");
461 /* [V] the detach here may segfault on 1.1 JVM... */
462 detach_from_jvm(p, l);
467 p->was_verified = JK_TRUE;
474 static int JK_METHOD init(jk_worker_t *pThis,
476 jk_worker_env_t *we, jk_logger_t *l)
483 if (!pThis || !pThis->worker_private) {
484 JK_LOG_NULL_PARAMS(l);
489 p = pThis->worker_private;
491 if (p->was_initialized) {
492 jk_log(l, JK_LOG_DEBUG, "done (been here!)");
498 !p->jk_java_bridge_object ||
499 !p->jk_service_method ||
500 !p->jk_startup_method || !p->jk_shutdown_method) {
501 jk_log(l, JK_LOG_EMERG, "worker not set completely");
506 /* [V] init is called from the same thread that called validate */
507 /* there is no need to attach to the JVM, just get the env */
509 /* if(env = attach_to_jvm(p,l)) { */
510 if ((env = p->tmp_env)) {
511 jstring cmd_line = (jstring) NULL;
512 jstring stdout_name = (jstring) NULL;
513 jstring stderr_name = (jstring) NULL;
516 /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */
518 if (p->tomcat_cmd_line) {
520 (*env)->NewStringUTF(env,
521 strdup_ascii(&p->p, p->tomcat_cmd_line));
523 if (p->stdout_name) {
525 (*env)->NewStringUTF(env,
526 strdup_ascii(&p->p, p->stdout_name));
528 if (p->stderr_name) {
530 (*env)->NewStringUTF(env,
531 strdup_ascii(&p->p, p->stderr_name));
534 jk_log(l, JK_LOG_DEBUG,
535 "calling Tomcat to intialize itself...");
536 rc = (*env)->CallIntMethod(env, p->jk_java_bridge_object,
537 p->jk_startup_method, cmd_line,
538 stdout_name, stderr_name);
540 detach_from_jvm(p, l);
543 p->was_initialized = JK_TRUE;
544 jk_log(l, JK_LOG_DEBUG, "Tomcat initialized OK, done");
549 jk_log(l, JK_LOG_EMERG, "could not initialize Tomcat");
555 jk_log(l, JK_LOG_ERROR,
556 "In init, FIXME: init didn't gen env from validate!");
562 static int JK_METHOD get_endpoint(jk_worker_t *pThis,
563 jk_endpoint_t **pend, jk_logger_t *l)
565 /* [V] This slow, needs replacement */
570 if (!pThis || !pThis->worker_private || !pend) {
571 JK_LOG_NULL_PARAMS(l);
576 p = (jni_endpoint_t *) calloc(1, sizeof(jni_endpoint_t));
578 p->attached = JK_FALSE;
580 p->worker = pThis->worker_private;
581 p->endpoint.endpoint_private = p;
582 p->endpoint.service = service;
583 p->endpoint.done = done;
584 *pend = &p->endpoint;
590 jk_log(l, JK_LOG_ERROR,
591 "could not allocate endpoint");
597 static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
604 if (!pThis || !*pThis || !(*pThis)->worker_private) {
605 JK_LOG_NULL_PARAMS(l);
610 p = (*pThis)->worker_private;
613 jk_log(l, JK_LOG_DEBUG, "JVM not intantiated");
618 if (!p->jk_java_bridge_object || !p->jk_shutdown_method) {
619 jk_log(l, JK_LOG_DEBUG, "Tomcat not intantiated");
624 if ((env = attach_to_jvm(p, l))) {
625 jk_log(l, JK_LOG_DEBUG, "shutting down Tomcat...");
626 (*env)->CallVoidMethod(env,
627 p->jk_java_bridge_object,
628 p->jk_shutdown_method);
629 detach_from_jvm(p, l);
632 jk_close_pool(&p->p);
635 jk_log(l, JK_LOG_DEBUG, "destroyed");
641 int JK_METHOD jni_worker_factory(jk_worker_t **w,
642 const char *name, jk_logger_t *l)
644 jni_worker_t *private_data;
648 jk_log(l, JK_LOG_WARNING,
649 "Worker '%s' is of type jni, which is deprecated "
650 "and will be removed in a future release.",
651 name ? name : "(null)");
654 JK_LOG_NULL_PARAMS(l);
659 if (the_singleton_jni_worker) {
660 jk_log(l, JK_LOG_DEBUG,
661 "instance already created");
662 *w = the_singleton_jni_worker;
664 return JK_JNI_WORKER_TYPE;
667 private_data = (jni_worker_t *) malloc(sizeof(jni_worker_t));
670 jk_log(l, JK_LOG_ERROR,
671 "memory allocation error");
676 jk_open_pool(&private_data->p,
677 private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
679 private_data->name = jk_pool_strdup(&private_data->p, name);
681 if (!private_data->name) {
682 jk_log(l, JK_LOG_ERROR,
683 "memory allocation error");
684 jk_close_pool(&private_data->p);
690 private_data->was_verified = JK_FALSE;
691 private_data->was_initialized = JK_FALSE;
692 private_data->jvm = NULL;
693 private_data->tmp_env = NULL;
694 private_data->jk_java_bridge_object = (jobject) NULL;
695 private_data->jk_java_bridge_class = (jclass) NULL;
696 private_data->jk_startup_method = (jmethodID) NULL;
697 private_data->jk_service_method = (jmethodID) NULL;
698 private_data->jk_shutdown_method = (jmethodID) NULL;
699 private_data->tomcat_cmd_line = NULL;
700 private_data->tomcat_classpath = NULL;
701 private_data->bridge_type = TC33_BRIDGE_TYPE;
702 private_data->jvm_dll_path = NULL;
703 private_data->tomcat_ms = 0;
704 private_data->tomcat_mx = 0;
705 private_data->sysprops = NULL;
706 #ifdef JNI_VERSION_1_2
707 private_data->java2opts = NULL;
708 private_data->java2lax = JK_TRUE;
710 private_data->stdout_name = NULL;
711 private_data->stderr_name = NULL;
713 private_data->worker.worker_private = private_data;
714 private_data->worker.validate = validate;
715 private_data->worker.init = init;
716 private_data->worker.get_endpoint = get_endpoint;
717 private_data->worker.destroy = destroy;
719 *w = &private_data->worker;
720 the_singleton_jni_worker = &private_data->worker;
723 return JK_JNI_WORKER_TYPE;
726 static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l)
729 HINSTANCE hInst = LoadLibrary(p->jvm_dll_path);
731 (FARPROC) jni_create_java_vm =
732 GetProcAddress(hInst, "JNI_CreateJavaVM");
734 (FARPROC) jni_get_created_java_vms =
735 GetProcAddress(hInst, "JNI_GetCreatedJavaVMs");
737 (FARPROC) jni_get_default_java_vm_init_args =
738 GetProcAddress(hInst, "JNI_GetDefaultJavaVMInitArgs");
740 jk_log(l, JK_LOG_DEBUG, "Loaded all JNI procs");
742 if (jni_create_java_vm && jni_get_default_java_vm_init_args
743 && jni_get_created_java_vms) {
749 #elif defined(NETWARE) && !defined(__NOVELL_LIBC__)
750 int javaNlmHandle = FindNLMHandle("JVM");
751 if (0 == javaNlmHandle) {
752 /* if we didn't get a handle, try to load java and retry getting the */
754 spawnlp(P_NOWAIT, "JVM.NLM", NULL);
755 ThreadSwitchWithDelay();
756 javaNlmHandle = FindNLMHandle("JVM");
757 if (0 == javaNlmHandle)
758 printf("Error loading Java.");
761 if (0 != javaNlmHandle) {
762 jni_create_java_vm = ImportSymbol(GetNLMHandle(), "JNI_CreateJavaVM");
763 jni_get_created_java_vms =
764 ImportSymbol(GetNLMHandle(), "JNI_GetCreatedJavaVMs");
765 jni_get_default_java_vm_init_args =
766 ImportSymbol(GetNLMHandle(), "JNI_GetDefaultJavaVMInitArgs");
768 if (jni_create_java_vm && jni_get_default_java_vm_init_args
769 && jni_get_created_java_vms) {
773 jk_log(l, JK_LOG_DEBUG,
774 "Direct reference to JNI entry points (no SRVPGM)");
775 jni_create_java_vm = &JNI_CreateJavaVM;
776 jni_get_default_java_vm_init_args = &JNI_GetDefaultJavaVMInitArgs;
777 jni_get_created_java_vms = &JNI_GetCreatedJavaVMs;
780 jk_log(l, JK_LOG_DEBUG, "loading JVM %s", p->jvm_dll_path);
782 handle = dlopen(p->jvm_dll_path, RTLD_NOW | RTLD_GLOBAL);
785 jk_log(l, JK_LOG_EMERG,
786 "Can't load native library %s : %s", p->jvm_dll_path,
790 jni_create_java_vm = dlsym(handle, "JNI_CreateJavaVM");
791 jni_get_default_java_vm_init_args =
792 dlsym(handle, "JNI_GetDefaultJavaVMInitArgs");
793 jni_get_created_java_vms = dlsym(handle, "JNI_GetCreatedJavaVMs");
795 if (jni_create_java_vm && jni_get_default_java_vm_init_args &&
796 jni_get_created_java_vms) {
797 jk_log(l, JK_LOG_DEBUG,
798 "In load_jvm_dll, symbols resolved, done");
801 jk_log(l, JK_LOG_EMERG,
802 "Can't resolve JNI_CreateJavaVM or JNI_GetDefaultJavaVMInitArgs");
809 static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
811 #ifdef JNI_VERSION_1_2
812 int jvm_version = detect_jvm_version(l);
814 switch (jvm_version) {
815 case JNI_VERSION_1_1:
816 return open_jvm1(p, env, l);
817 case JNI_VERSION_1_2:
818 return open_jvm2(p, env, l);
823 /* [V] Make sure this is _really_ visible */
824 #warning -------------------------------------------------------
825 #warning NO JAVA 2 HEADERS! SUPPORT FOR JAVA 2 FEATURES DISABLED
826 #warning -------------------------------------------------------
827 return open_jvm1(p, env, l);
831 static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
833 JDK1_1InitArgs vm_args;
840 vm_args.version = JNI_VERSION_1_1;
842 if (0 != jni_get_default_java_vm_init_args(&vm_args)) {
843 jk_log(l, JK_LOG_EMERG, "can't get default vm init args");
847 jk_log(l, JK_LOG_DEBUG, "got default jvm args");
849 if (vm_args.classpath) {
850 size_t len = strlen(vm_args.classpath) +
851 strlen(p->tomcat_classpath) + 3;
852 char *tmp = jk_pool_alloc(&p->p, len);
854 sprintf(tmp, "%s%c%s",
855 strdup_ascii(&p->p, p->tomcat_classpath),
856 PATH_SEPERATOR, vm_args.classpath);
857 p->tomcat_classpath = tmp;
860 jk_log(l, JK_LOG_EMERG,
861 "allocation error for classpath");
866 vm_args.classpath = p->tomcat_classpath;
869 vm_args.maxHeapSize = p->tomcat_mx;
873 vm_args.minHeapSize = p->tomcat_ms;
877 /* No EBCDIC to ASCII conversion here for AS/400 - later */
878 vm_args.properties = p->sysprops;
881 jk_log(l, JK_LOG_DEBUG, "In open_jvm1, about to create JVM...");
882 if ((err = jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) {
883 jk_log(l, JK_LOG_EMERG,
884 "could not create JVM, code: %d ", err);
888 jk_log(l, JK_LOG_DEBUG, "JVM created, done");
896 #ifdef JNI_VERSION_1_2
897 static int detect_jvm_version(jk_logger_t *l)
900 JDK1_1InitArgs vm_args;
904 /* [V] Idea: ask for 1.2. If the JVM is 1.1 it will return 1.1 instead */
905 /* Note: asking for 1.1 won't work, 'cause 1.2 JVMs will return 1.1 */
906 vm_args.version = JNI_VERSION_1_2;
908 if (0 != jni_get_default_java_vm_init_args(&vm_args)) {
909 jk_log(l, JK_LOG_EMERG, "can't get default vm init args");
913 jk_log(l, JK_LOG_DEBUG,
914 "found version: %X, done", vm_args.version);
917 return vm_args.version;
920 static char *build_opt_str(jk_pool_t *p,
921 char *opt_name, char *opt_value, jk_logger_t *l)
923 size_t len = strlen(opt_name) + strlen(opt_value) + 2;
925 /* [V] IMHO, these should not be deallocated as long as the JVM runs */
926 char *tmp = jk_pool_alloc(p, len);
929 sprintf(tmp, "%s%s", opt_name, opt_value);
933 jk_log(l, JK_LOG_EMERG,
934 "allocation error for %s", opt_name);
939 static char *build_opt_int(jk_pool_t *p,
940 char *opt_name, int opt_value, jk_logger_t *l)
942 /* [V] this should suffice even for 64-bit int */
943 size_t len = strlen(opt_name) + 20 + 2;
944 /* [V] IMHO, these should not be deallocated as long as the JVM runs */
945 char *tmp = jk_pool_alloc(p, len);
948 sprintf(tmp, "%s%d", opt_name, opt_value);
952 jk_log(l, JK_LOG_EMERG,
953 "allocation error for %s", opt_name);
958 static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
960 JavaVMInitArgs vm_args;
962 JavaVMOption options[100];
970 vm_args.version = JNI_VERSION_1_2;
971 vm_args.options = options;
973 /* AS/400 need EBCDIC to ASCII conversion to parameters passed to JNI */
974 /* No conversion for ASCII based systems (what about BS2000 ?) */
976 if (p->tomcat_classpath) {
977 jk_log(l, JK_LOG_DEBUG, "setting classpath to %s",
978 p->tomcat_classpath);
980 build_opt_str(&p->p, "-Djava.class.path=", p->tomcat_classpath,
983 options[optn++].optionString = strdup_ascii(&p->p, tmp);
987 jk_log(l, JK_LOG_DEBUG, "setting max heap to %d",
989 tmp = build_opt_int(&p->p, "-Xmx", p->tomcat_mx, l);
991 options[optn++].optionString = strdup_ascii(&p->p, tmp);
995 jk_log(l, JK_LOG_DEBUG, "setting start heap to %d",
997 tmp = build_opt_int(&p->p, "-Xms", p->tomcat_ms, l);
999 options[optn++].optionString = strdup_ascii(&p->p, tmp);
1004 while (p->sysprops[i]) {
1005 jk_log(l, JK_LOG_DEBUG, "setting %s",
1007 tmp = build_opt_str(&p->p, "-D", p->sysprops[i], l);
1009 options[optn++].optionString = strdup_ascii(&p->p, tmp);
1017 while (p->java2opts[i]) {
1018 jk_log(l, JK_LOG_DEBUG, "using option: %s",
1020 /* Pass it "as is" */
1021 options[optn++].optionString =
1022 strdup_ascii(&p->p, p->java2opts[i++]);
1026 vm_args.nOptions = optn;
1029 jk_log(l, JK_LOG_DEBUG,
1030 "the JVM will ignore unknown options");
1031 vm_args.ignoreUnrecognized = JNI_TRUE;
1034 jk_log(l, JK_LOG_DEBUG,
1035 "the JVM will FAIL if it finds unknown options");
1036 vm_args.ignoreUnrecognized = JNI_FALSE;
1039 jk_log(l, JK_LOG_DEBUG, "about to create JVM...");
1041 err = jni_create_java_vm(&(p->jvm), &penv, &vm_args);
1043 if (JNI_EEXIST == err) {
1049 jk_log(l, JK_LOG_DEBUG, "JVM alread instantiated."
1050 "Trying to attach instead.");
1052 jni_get_created_java_vms(&(p->jvm), 1, &vmCount);
1054 penv = attach_to_jvm(p, l);
1061 jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d ",
1068 jk_log(l, JK_LOG_DEBUG, "JVM created");
1075 static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l)
1080 jmethodID constructor_method_id;
1084 switch (p->bridge_type) {
1085 case TC32_BRIDGE_TYPE:
1086 btype = TC32_JAVA_BRIDGE_CLASS_NAME;
1089 case TC33_BRIDGE_TYPE:
1090 btype = TC33_JAVA_BRIDGE_CLASS_NAME;
1093 case TC40_BRIDGE_TYPE:
1094 case TC41_BRIDGE_TYPE:
1095 case TC50_BRIDGE_TYPE:
1096 jk_log(l, JK_LOG_EMERG, "Bridge type %d not supported",
1102 /* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */
1103 /* for others, strdup_ascii is just jk_pool_strdup */
1105 ctype = strdup_ascii(&p->p, btype);
1107 p->jk_java_bridge_class = (*env)->FindClass(env, ctype);
1109 if (!p->jk_java_bridge_class) {
1110 jk_log(l, JK_LOG_EMERG, "Can't find class %s", btype);
1114 jk_log(l, JK_LOG_DEBUG,
1115 "In get_bridge_object, loaded %s bridge class", btype);
1117 constructor_method_id = (*env)->GetMethodID(env, p->jk_java_bridge_class, strdup_ascii(&p->p, "<init>"), /* method name */
1118 strdup_ascii(&p->p, "()V")); /* method sign */
1120 if (!constructor_method_id) {
1121 p->jk_java_bridge_class = (jclass) NULL;
1122 jk_log(l, JK_LOG_EMERG, "Can't find constructor");
1127 p->jk_java_bridge_object = (*env)->NewObject(env,
1128 p->jk_java_bridge_class,
1129 constructor_method_id);
1130 if (!p->jk_java_bridge_object) {
1131 p->jk_java_bridge_class = (jclass) NULL;
1132 jk_log(l, JK_LOG_EMERG, "Can't create new bridge object");
1137 p->jk_java_bridge_object =
1138 (jobject) (*env)->NewGlobalRef(env, p->jk_java_bridge_object);
1139 if (!p->jk_java_bridge_object) {
1140 jk_log(l, JK_LOG_EMERG, "Can't create global ref to bridge object");
1141 p->jk_java_bridge_class = (jclass) NULL;
1142 p->jk_java_bridge_object = (jobject) NULL;
1151 static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l)
1154 /* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */
1156 p->jk_startup_method = (*env)->GetMethodID(env,
1157 p->jk_java_bridge_class,
1158 strdup_ascii(&p->p, "startup"),
1160 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I"));
1162 if (!p->jk_startup_method) {
1163 jk_log(l, JK_LOG_EMERG, "Can't find startup()");
1167 p->jk_service_method = (*env)->GetMethodID(env,
1168 p->jk_java_bridge_class,
1169 strdup_ascii(&p->p, "service"),
1170 strdup_ascii(&p->p, "(JJ)I"));
1172 if (!p->jk_service_method) {
1173 jk_log(l, JK_LOG_EMERG, "Can't find service()");
1177 p->jk_shutdown_method = (*env)->GetMethodID(env,
1178 p->jk_java_bridge_class,
1181 strdup_ascii(&p->p, "()V"));
1183 if (!p->jk_shutdown_method) {
1184 jk_log(l, JK_LOG_EMERG, "Can't find shutdown()");
1191 static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l)
1194 /* [V] This message is important. If there are signal mask issues, *
1195 * the JVM usually hangs when a new thread tries to attach to it */
1198 #if defined LINUX && defined APACHE2_SIGHACK
1199 linux_signal_hack();
1202 if (0 == (*(p->jvm))->AttachCurrentThread(p->jvm,
1203 #ifdef JNI_VERSION_1_2
1207 jk_log(l, JK_LOG_DEBUG, "In attach_to_jvm, attached ok");
1211 jk_log(l, JK_LOG_ERROR,
1212 "In attach_to_jvm, cannot attach thread to JVM.");
1218 static JNIEnv *attach_to_jvm(jni_worker_t *p)
1223 linux_signal_hack();
1226 if(0 == (*(p->jvm))->AttachCurrentThread(p->jvm,
1227 #ifdef JNI_VERSION_1_2
1238 static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l)
1241 if (!p->jvm || !(*(p->jvm))) {
1242 jk_log(l, JK_LOG_ERROR,
1243 "cannot detach from NULL JVM.");
1246 if (0 == (*(p->jvm))->DetachCurrentThread(p->jvm)) {
1247 jk_log(l, JK_LOG_DEBUG, "detached ok");
1250 jk_log(l, JK_LOG_ERROR,
1251 "cannot detach from JVM.");
1256 int JK_METHOD jni_worker_factory(jk_worker_t **w,
1257 const char *name, jk_logger_t *l)
1259 jk_log(l, JK_LOG_WARNING,
1260 "Worker '%s' is of type jni, which is deprecated "
1261 "and will be removed in a future release.",
1262 name ? name : "(null)");
1267 #endif /* JNI_VERSION_1_6 */