📄 jk_channel_jni.c
字号:
/* ========================================================================= * * * * The Apache Software License, Version 1.1 * * * * Copyright (c) 1999-2002 The Apache Software Foundation. * * All rights reserved. * * * * ========================================================================= * * * * Redistribution and use in source and binary forms, with or without modi- * * fication, are permitted provided that the following conditions are met: * * * * 1. Redistributions of source code must retain the above copyright notice * * notice, this list of conditions and the following disclaimer. * * * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * * * 3. The end-user documentation included with the redistribution, if any, * * must include the following acknowlegement: * * * * "This product includes software developed by the Apache Software * * Foundation <http://www.apache.org/>." * * * * Alternately, this acknowlegement may appear in the software itself, if * * and wherever such third-party acknowlegements normally appear. * * * * 4. The names "The Jakarta Project", "Jk", and "Apache Software * * Foundation" must not be used to endorse or promote products derived * * from this software without prior written permission. For written * * permission, please contact <apache@apache.org>. * * * * 5. Products derived from this software may not be called "Apache" nor may * * "Apache" appear in their names without prior written permission of the * * Apache Software Foundation. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES * * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * * THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY * * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * * POSSIBILITY OF SUCH DAMAGE. * * * * ========================================================================= * * * * This software consists of voluntary contributions made by many indivi- * * duals on behalf of the Apache Software Foundation. For more information * * on the Apache Software Foundation, please see <http://www.apache.org/>. * * * * ========================================================================= *//** * Channel using jni calls ( assuming in-process tomcat ). * * @author: Gal Shachor <shachor@il.ibm.com> * @author: Costin Manolache */#include "jk_workerEnv.h"#include "jk_env.h"#include "jk_bean.h"#ifdef HAVE_JNI#include "jk_map.h"#include "jk_env.h"#include "jk_channel.h"#include "jk_global.h"#include <string.h>#include "jk_registry.h"#include <jni.h>/* default only, is configurable now */#define JAVA_BRIDGE_CLASS_NAME ("org/apache/jk/apr/AprImpl")#define JNI_TOMCAT_STARTED 2extern int jk_jni_status_code;/** Information specific for the socket channel */typedef struct { jk_vm_t *vm; char *className; jclass jniBridge; jmethodID writeMethod; int status;} jk_channel_jni_private_t;typedef struct { JNIEnv *jniEnv; int len; jbyteArray jarray; char *carray; int arrayLen; jobject jniJavaContext;/* jobject msgJ; */} jk_ch_jni_ep_private_t;/* Duplicate string and convert it to ASCII on EBDIC based systems Needed for at least AS/400 and BS2000 but what about other EBDIC systems ?*/static void *strdup_ascii(jk_env_t *env, char *s){#if defined(AS400) || defined(_OSD_POSIX) return (env->tmpPool->pstrdup2ascii(env, env->tmpPool, s));#else return (env->tmpPool->pstrdup(env, env->tmpPool, s));#endif}static int JK_METHOD jk2_channel_jni_init(jk_env_t *env, jk_bean_t *jniWB){ jk_channel_t *jniW=jniWB->object; jk_workerEnv_t *wEnv=jniW->workerEnv; if (wEnv->childId != 0) { if( jniW->worker != NULL ) jniW->worker->mbean->disabled=JK_TRUE; return JK_ERR; } if( wEnv->vm == NULL ) { env->l->jkLog(env, env->l, JK_LOG_INFO, "channel_jni.init() no VM found\n" ); if( jniW->worker != NULL ) { jniW->worker->mbean->disabled=JK_TRUE; } return JK_ERR; } return JK_OK;}/** Assume the jni-worker or someone else started * tomcat and initialized what is needed. */static int JK_METHOD jk2_channel_jni_open(jk_env_t *env, jk_channel_t *_this, jk_endpoint_t *endpoint){ jk_workerEnv_t *we=endpoint->worker->workerEnv; JNIEnv *jniEnv; jk_ch_jni_ep_private_t *epData; jmethodID jmethod; jobject jobj; jstring jstr; jk_channel_jni_private_t *jniCh=_this->_privatePtr; if( endpoint->channelData != NULL ) { env->l->jkLog(env, env->l, JK_LOG_INFO, "channel_jni.open() already open, nothing else to do\n"); return JK_OK; } env->l->jkLog(env, env->l, JK_LOG_INFO,"channel_jni.open(): \n" ); /* It is useless to continue if the channel worker does not exist. */ if( _this->worker == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() NullPointerException, no channel worker found\n"); return JK_ERR; } jniCh->vm=(jk_vm_t *)we->vm; if( jniCh->vm == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() no VM found\n" ); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } jniEnv = (JNIEnv *)jniCh->vm->attach( env, jniCh->vm ); if( jniEnv == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() can't attach\n" ); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } /* Create the buffers used by the write method. We allocate a byte[] and jbyte[] - I have no idea what's more expensive, to copy a buffer or to 'pin' the jbyte[] for copying. This will be tuned if needed, for now it seems the easiest solution */ epData=(jk_ch_jni_ep_private_t *) endpoint->mbean->pool->calloc( env,endpoint->mbean->pool, sizeof( jk_ch_jni_ep_private_t )); endpoint->channelData=epData; /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ jniCh->jniBridge = (*jniEnv)->FindClass(jniEnv, strdup_ascii(env, jniCh->className) ); if( jniCh->jniBridge == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() can't find %s\n",jniCh->className ); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } jniCh->jniBridge=(*jniEnv)->NewGlobalRef( jniEnv, jniCh->jniBridge); if( jniCh->jniBridge == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() Unable to allocate globalref for %s\n",jniCh->className ); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } /* Interface to the callback mechansim. The idea is simple ( is it ? ) - we use a similar pattern with java, trying to do as little as possible in C and pass minimal information to allow this. The pattern used for callback works for our message forwarding but also for other things - like singnals, etc */ /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ jmethod=(*jniEnv)->GetStaticMethodID(jniEnv, jniCh->jniBridge, strdup_ascii(env, "createJavaContext"), strdup_ascii(env, "(Ljava/lang/String;J)Ljava/lang/Object;")); if( jmethod == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() can't find createJavaContext\n"); _this->worker->mbean->disabled=JK_TRUE; if( (*jniEnv)->ExceptionCheck( jniEnv ) ) { (*jniEnv)->ExceptionClear( jniEnv ); } return JK_ERR; } /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ jstr=(*jniEnv)->NewStringUTF(jniEnv, strdup_ascii(env, "channelJni" )); jobj=(*jniEnv)->CallStaticObjectMethod( jniEnv, jniCh->jniBridge, jmethod, jstr, (jlong)(long)(void *)endpoint->mbean ); if( jobj == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() Can't create java context\n" ); epData->jniJavaContext=NULL; _this->worker->mbean->disabled=JK_TRUE; if( (*jniEnv)->ExceptionCheck( jniEnv ) ) { (*jniEnv)->ExceptionClear( jniEnv ); } return JK_ERR; } epData->jniJavaContext=(*jniEnv)->NewGlobalRef( jniEnv, jobj ); env->l->jkLog(env, env->l, JK_LOG_INFO, "channel_jni.open() Got ep %#lx %#lx\n", jobj, epData->jniJavaContext ); /* XXX Destroy them in close */ /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ jmethod=(*jniEnv)->GetStaticMethodID(jniEnv, jniCh->jniBridge, strdup_ascii(env, "getBuffer"), strdup_ascii(env, "(Ljava/lang/Object;I)[B")); if( jmethod == NULL ) { env->l->jkLog(env, env->l, JK_LOG_ERROR, "channel_jni.open() can't find getBuffer\n"); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } epData->jarray=(*jniEnv)->CallStaticObjectMethod( jniEnv, jniCh->jniBridge, jmethod, epData->jniJavaContext, 0); epData->jarray=(*jniEnv)->NewGlobalRef( jniEnv, epData->jarray ); epData->arrayLen = (*jniEnv)->GetArrayLength( jniEnv, epData->jarray ); /* XXX > ajp buffer size. Don't know how to fragment or reallocate yet */ epData->carray=(char *)endpoint->mbean->pool->calloc( env, endpoint->mbean->pool, epData->arrayLen); /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */ jniCh->writeMethod = (*jniEnv)->GetStaticMethodID(jniEnv, jniCh->jniBridge, strdup_ascii(env, "jniInvoke"), strdup_ascii(env, "(JLjava/lang/Object;)I")); if( jniCh->writeMethod == NULL ) { env->l->jkLog(env, env->l, JK_LOG_EMERG, "channel_jni.open() can't find jniInvoke\n"); _this->worker->mbean->disabled=JK_TRUE; return JK_ERR; } env->l->jkLog(env, env->l, JK_LOG_INFO, "channel_jni.open() found write method, open ok\n" ); _this->worker->mbean->disabled=JK_FALSE; /* Don't detach ( XXX Need to find out when the thread is * closing in order for this to work ) */ /* jniCh->vm->detach( env, jniCh->vm ); */ return JK_OK;}/** */static int JK_METHOD jk2_channel_jni_close(jk_env_t *env,jk_channel_t *_this, jk_endpoint_t *endpoint){ jk_ch_jni_ep_private_t *epData; JNIEnv *jniEnv; jk_channel_jni_private_t *jniCh=_this->_privatePtr; epData=(jk_ch_jni_ep_private_t *)endpoint->channelData; if (epData == NULL) { env->l->jkLog(env, env->l, JK_LOG_INFO,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -