Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "JNIUtility.h"
     28 
     29 #if ENABLE(MAC_JAVA_BRIDGE)
     30 
     31 #include <dlfcn.h>
     32 
     33 namespace JSC {
     34 
     35 namespace Bindings {
     36 
     37 static jint KJSGetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs)
     38 {
     39     static void* javaVMFramework = 0;
     40     if (!javaVMFramework)
     41         javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY);
     42     if (!javaVMFramework)
     43         return JNI_ERR;
     44 
     45     typedef jint(*FunctionPointerType)(JavaVM**, jsize, jsize*);
     46     static FunctionPointerType functionPointer = 0;
     47     if (!functionPointer)
     48         functionPointer = reinterpret_cast<FunctionPointerType>(dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"));
     49     if (!functionPointer)
     50         return JNI_ERR;
     51     return functionPointer(vmBuf, bufLen, nVMs);
     52 }
     53 
     54 static JavaVM* jvm = 0;
     55 
     56 // Provide the ability for an outside component to specify the JavaVM to use
     57 // If the jvm value is set, the getJavaVM function below will just return.
     58 // In getJNIEnv(), if AttachCurrentThread is called to a VM that is already
     59 // attached, the result is a no-op.
     60 void setJavaVM(JavaVM* javaVM)
     61 {
     62     jvm = javaVM;
     63 }
     64 
     65 JavaVM* getJavaVM()
     66 {
     67     if (jvm)
     68         return jvm;
     69 
     70     JavaVM* jvmArray[1];
     71     jsize bufLen = 1;
     72     jsize nJVMs = 0;
     73     jint jniError = 0;
     74 
     75     // Assumes JVM is already running ..., one per process
     76     jniError = KJSGetCreatedJavaVMs(jvmArray, bufLen, &nJVMs);
     77     if (jniError == JNI_OK && nJVMs > 0)
     78         jvm = jvmArray[0];
     79     else
     80         fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, static_cast<long>(jniError));
     81 
     82     return jvm;
     83 }
     84 
     85 JNIEnv* getJNIEnv()
     86 {
     87     union {
     88         JNIEnv* env;
     89         void* dummy;
     90     } u;
     91     jint jniError = 0;
     92 
     93     jniError = getJavaVM()->AttachCurrentThread(&u.dummy, 0);
     94     if (jniError == JNI_OK)
     95         return u.env;
     96     fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, static_cast<long>(jniError));
     97     return 0;
     98 }
     99 
    100 jmethodID getMethodID(jobject obj, const char* name, const char* sig)
    101 {
    102     JNIEnv* env = getJNIEnv();
    103     jmethodID mid = 0;
    104 
    105     if (env) {
    106         jclass cls = env->GetObjectClass(obj);
    107         if (cls) {
    108             mid = env->GetMethodID(cls, name, sig);
    109             if (!mid) {
    110                 env->ExceptionClear();
    111                 mid = env->GetStaticMethodID(cls, name, sig);
    112                 if (!mid)
    113                     env->ExceptionClear();
    114             }
    115         }
    116         env->DeleteLocalRef(cls);
    117     }
    118     return mid;
    119 }
    120 
    121 const char* getCharactersFromJString(jstring aJString)
    122 {
    123     return getCharactersFromJStringInEnv(getJNIEnv(), aJString);
    124 }
    125 
    126 void releaseCharactersForJString(jstring aJString, const char* s)
    127 {
    128     releaseCharactersForJStringInEnv(getJNIEnv(), aJString, s);
    129 }
    130 
    131 const char* getCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
    132 {
    133     jboolean isCopy;
    134     const char* s = env->GetStringUTFChars(aJString, &isCopy);
    135     if (!s) {
    136         env->ExceptionDescribe();
    137         env->ExceptionClear();
    138         fprintf(stderr, "\n");
    139     }
    140     return s;
    141 }
    142 
    143 void releaseCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const char* s)
    144 {
    145     env->ReleaseStringUTFChars(aJString, s);
    146 }
    147 
    148 const jchar* getUCharactersFromJStringInEnv(JNIEnv* env, jstring aJString)
    149 {
    150     jboolean isCopy;
    151     const jchar* s = env->GetStringChars(aJString, &isCopy);
    152     if (!s) {
    153         env->ExceptionDescribe();
    154         env->ExceptionClear();
    155         fprintf(stderr, "\n");
    156     }
    157     return s;
    158 }
    159 
    160 void releaseUCharactersForJStringInEnv(JNIEnv* env, jstring aJString, const jchar* s)
    161 {
    162     env->ReleaseStringChars(aJString, s);
    163 }
    164 
    165 JNIType JNITypeFromClassName(const char* name)
    166 {
    167     JNIType type;
    168 
    169     if (!strcmp("byte", name))
    170         type = byte_type;
    171     else if (!strcmp("short", name))
    172         type = short_type;
    173     else if (!strcmp("int", name))
    174         type = int_type;
    175     else if (!strcmp("long", name))
    176         type = long_type;
    177     else if (!strcmp("float", name))
    178         type = float_type;
    179     else if (!strcmp("double", name))
    180         type = double_type;
    181     else if (!strcmp("char", name))
    182         type = char_type;
    183     else if (!strcmp("boolean", name))
    184         type = boolean_type;
    185     else if (!strcmp("void", name))
    186         type = void_type;
    187     else if ('[' == name[0])
    188         type = array_type;
    189     else
    190         type = object_type;
    191 
    192     return type;
    193 }
    194 
    195 const char* signatureFromPrimitiveType(JNIType type)
    196 {
    197     switch (type) {
    198     case void_type:
    199         return "V";
    200 
    201     case array_type:
    202         return "[";
    203 
    204     case object_type:
    205         return "L";
    206 
    207     case boolean_type:
    208         return "Z";
    209 
    210     case byte_type:
    211         return "B";
    212 
    213     case char_type:
    214         return "C";
    215 
    216     case short_type:
    217         return "S";
    218 
    219     case int_type:
    220         return "I";
    221 
    222     case long_type:
    223         return "J";
    224 
    225     case float_type:
    226         return "F";
    227 
    228     case double_type:
    229         return "D";
    230 
    231     case invalid_type:
    232     default:
    233         break;
    234     }
    235     return "";
    236 }
    237 
    238 JNIType JNITypeFromPrimitiveType(char type)
    239 {
    240     switch (type) {
    241     case 'V':
    242         return void_type;
    243 
    244     case 'L':
    245         return object_type;
    246 
    247     case '[':
    248         return array_type;
    249 
    250     case 'Z':
    251         return boolean_type;
    252 
    253     case 'B':
    254         return byte_type;
    255 
    256     case 'C':
    257         return char_type;
    258 
    259     case 'S':
    260         return short_type;
    261 
    262     case 'I':
    263         return int_type;
    264 
    265     case 'J':
    266         return long_type;
    267 
    268     case 'F':
    269         return float_type;
    270 
    271     case 'D':
    272         return double_type;
    273 
    274     default:
    275         break;
    276     }
    277     return invalid_type;
    278 }
    279 
    280 jvalue getJNIField(jobject obj, JNIType type, const char* name, const char* signature)
    281 {
    282     JavaVM* jvm = getJavaVM();
    283     JNIEnv* env = getJNIEnv();
    284     jvalue result;
    285 
    286     memset(&result, 0, sizeof(jvalue));
    287     if (obj && jvm && env) {
    288         jclass cls = env->GetObjectClass(obj);
    289         if (cls) {
    290             jfieldID field = env->GetFieldID(cls, name, signature);
    291             if (field) {
    292                 switch (type) {
    293                 case array_type:
    294                 case object_type:
    295                     result.l = env->functions->GetObjectField(env, obj, field);
    296                     break;
    297                 case boolean_type:
    298                     result.z = env->functions->GetBooleanField(env, obj, field);
    299                     break;
    300                 case byte_type:
    301                     result.b = env->functions->GetByteField(env, obj, field);
    302                     break;
    303                 case char_type:
    304                     result.c = env->functions->GetCharField(env, obj, field);
    305                     break;
    306                 case short_type:
    307                     result.s = env->functions->GetShortField(env, obj, field);
    308                     break;
    309                 case int_type:
    310                     result.i = env->functions->GetIntField(env, obj, field);
    311                     break;
    312                 case long_type:
    313                     result.j = env->functions->GetLongField(env, obj, field);
    314                     break;
    315                 case float_type:
    316                     result.f = env->functions->GetFloatField(env, obj, field);
    317                     break;
    318                 case double_type:
    319                     result.d = env->functions->GetDoubleField(env, obj, field);
    320                     break;
    321                 default:
    322                     fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, static_cast<int>(type));
    323                 }
    324             } else {
    325                 fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name);
    326                 env->ExceptionDescribe();
    327                 env->ExceptionClear();
    328                 fprintf(stderr, "\n");
    329             }
    330 
    331             env->DeleteLocalRef(cls);
    332         } else
    333             fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__);
    334     }
    335 
    336     return result;
    337 }
    338 
    339 } // namespace Bindings
    340 
    341 } // namespace JSC
    342 
    343 #endif // ENABLE(MAC_JAVA_BRIDGE)
    344