source: proiecte/HadoopJUnit/hadoop-0.20.1/src/c++/libhdfs/hdfsJniHelper.c @ 141

Last change on this file since 141 was 120, checked in by (none), 14 years ago

Added the mail files for the Hadoop JUNit Project

  • Property svn:executable set to *
File size: 13.2 KB
Line 
1/**
2 * Copyright 2006 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string.h> 
18#include <error.h>
19#include "hdfsJniHelper.h"
20
21static pthread_mutex_t hdfsHashMutex = PTHREAD_MUTEX_INITIALIZER;
22static pthread_mutex_t jvmMutex = PTHREAD_MUTEX_INITIALIZER;
23static volatile int hashTableInited = 0;
24
25#define LOCK_HASH_TABLE() pthread_mutex_lock(&hdfsHashMutex)
26#define UNLOCK_HASH_TABLE() pthread_mutex_unlock(&hdfsHashMutex)
27#define LOCK_JVM_MUTEX() pthread_mutex_lock(&jvmMutex)
28#define UNLOCK_JVM_MUTEX() pthread_mutex_unlock(&jvmMutex)
29
30
31/** The Native return types that methods could return */
32#define VOID          'V'
33#define JOBJECT       'L'
34#define JARRAYOBJECT  '['
35#define JBOOLEAN      'Z'
36#define JBYTE         'B'
37#define JCHAR         'C'
38#define JSHORT        'S'
39#define JINT          'I'
40#define JLONG         'J'
41#define JFLOAT        'F'
42#define JDOUBLE       'D'
43
44
45/**
46 * MAX_HASH_TABLE_ELEM: The maximum no. of entries in the hashtable.
47 * It's set to 4096 to account for (classNames + No. of threads)
48 */
49#define MAX_HASH_TABLE_ELEM 4096
50
51
52static int validateMethodType(MethType methType)
53{
54    if (methType != STATIC && methType != INSTANCE) {
55        fprintf(stderr, "Unimplemented method type\n");
56        return 0;
57    }
58    return 1;
59}
60
61
62static int hashTableInit(void)
63{
64    if (!hashTableInited) {
65        LOCK_HASH_TABLE();
66        if (!hashTableInited) {
67            if (hcreate(MAX_HASH_TABLE_ELEM) == 0) {
68                fprintf(stderr, "error creating hashtable, <%d>: %s\n",
69                        errno, strerror(errno));
70                return 0;
71            } 
72            hashTableInited = 1;
73        }
74        UNLOCK_HASH_TABLE();
75    }
76    return 1;
77}
78
79
80static int insertEntryIntoTable(const char *key, void *data)
81{
82    ENTRY e, *ep;
83    if (key == NULL || data == NULL) {
84        return 0;
85    }
86    if (! hashTableInit()) {
87      return -1;
88    }
89    e.data = data;
90    e.key = (char*)key;
91    LOCK_HASH_TABLE();
92    ep = hsearch(e, ENTER);
93    UNLOCK_HASH_TABLE();
94    if (ep == NULL) {
95        fprintf(stderr, "warn adding key (%s) to hash table, <%d>: %s\n",
96                key, errno, strerror(errno));
97    } 
98    return 0;
99}
100
101
102
103static void* searchEntryFromTable(const char *key)
104{
105    ENTRY e,*ep;
106    if (key == NULL) {
107        return NULL;
108    }
109    hashTableInit();
110    e.key = (char*)key;
111    LOCK_HASH_TABLE();
112    ep = hsearch(e, FIND);
113    UNLOCK_HASH_TABLE();
114    if (ep != NULL) {
115        return ep->data;
116    }
117    return NULL;
118}
119
120
121
122int invokeMethod(JNIEnv *env, RetVal *retval, Exc *exc, MethType methType,
123                 jobject instObj, const char *className,
124                 const char *methName, const char *methSignature, ...)
125{
126    va_list args;
127    jclass cls;
128    jmethodID mid;
129    jthrowable jthr;
130    const char *str; 
131    char returnType;
132   
133    if (! validateMethodType(methType)) {
134      return -1;
135    }
136    cls = globalClassReference(className, env);
137    if (cls == NULL) {
138      return -2;
139    }
140
141    mid = methodIdFromClass(className, methName, methSignature, 
142                            methType, env);
143    if (mid == NULL) {
144        (*env)->ExceptionDescribe(env);
145        return -3;
146    }
147   
148    str = methSignature;
149    while (*str != ')') str++;
150    str++;
151    returnType = *str;
152    va_start(args, methSignature);
153    if (returnType == JOBJECT || returnType == JARRAYOBJECT) {
154        jobject jobj = NULL;
155        if (methType == STATIC) {
156            jobj = (*env)->CallStaticObjectMethodV(env, cls, mid, args);
157        }
158        else if (methType == INSTANCE) {
159            jobj = (*env)->CallObjectMethodV(env, instObj, mid, args);
160        }
161        retval->l = jobj;
162    }
163    else if (returnType == VOID) {
164        if (methType == STATIC) {
165            (*env)->CallStaticVoidMethodV(env, cls, mid, args);
166        }
167        else if (methType == INSTANCE) {
168            (*env)->CallVoidMethodV(env, instObj, mid, args);
169        }
170    }
171    else if (returnType == JBOOLEAN) {
172        jboolean jbool = 0;
173        if (methType == STATIC) {
174            jbool = (*env)->CallStaticBooleanMethodV(env, cls, mid, args);
175        }
176        else if (methType == INSTANCE) {
177            jbool = (*env)->CallBooleanMethodV(env, instObj, mid, args);
178        }
179        retval->z = jbool;
180    }
181    else if (returnType == JSHORT) {
182        jshort js = 0;
183        if (methType == STATIC) {
184            js = (*env)->CallStaticShortMethodV(env, cls, mid, args);
185        }
186        else if (methType == INSTANCE) {
187            js = (*env)->CallShortMethodV(env, instObj, mid, args);
188        }
189        retval->s = js;
190    }
191    else if (returnType == JLONG) {
192        jlong jl = -1;
193        if (methType == STATIC) {
194            jl = (*env)->CallStaticLongMethodV(env, cls, mid, args);
195        }
196        else if (methType == INSTANCE) {
197            jl = (*env)->CallLongMethodV(env, instObj, mid, args);
198        }
199        retval->j = jl;
200    }
201    else if (returnType == JINT) {
202        jint ji = -1;
203        if (methType == STATIC) {
204            ji = (*env)->CallStaticIntMethodV(env, cls, mid, args);
205        }
206        else if (methType == INSTANCE) {
207            ji = (*env)->CallIntMethodV(env, instObj, mid, args);
208        }
209        retval->i = ji;
210    }
211    va_end(args);
212
213    jthr = (*env)->ExceptionOccurred(env);
214    if (jthr != NULL) {
215        if (exc != NULL)
216            *exc = jthr;
217        else
218            (*env)->ExceptionDescribe(env);
219        return -1;
220    }
221    return 0;
222}
223
224jarray constructNewArrayString(JNIEnv *env, Exc *exc, const char **elements, int size) {
225  const char *className = "Ljava/lang/String;";
226  jobjectArray result;
227  int i;
228  jclass arrCls = (*env)->FindClass(env, className);
229  if (arrCls == NULL) {
230    fprintf(stderr, "could not find class %s\n",className);
231    return NULL; /* exception thrown */
232  }
233  result = (*env)->NewObjectArray(env, size, arrCls,
234                                  NULL);
235  if (result == NULL) {
236    fprintf(stderr, "ERROR: could not construct new array\n");
237    return NULL; /* out of memory error thrown */
238  }
239  for (i = 0; i < size; i++) {
240    jstring jelem = (*env)->NewStringUTF(env,elements[i]);
241    if (jelem == NULL) {
242      fprintf(stderr, "ERROR: jelem == NULL\n");
243    }
244    (*env)->SetObjectArrayElement(env, result, i, jelem);
245  }
246  return result;
247}
248
249jobject constructNewObjectOfClass(JNIEnv *env, Exc *exc, const char *className, 
250                                  const char *ctorSignature, ...)
251{
252    va_list args;
253    jclass cls;
254    jmethodID mid; 
255    jobject jobj;
256    jthrowable jthr;
257
258    cls = globalClassReference(className, env);
259    if (cls == NULL) {
260        (*env)->ExceptionDescribe(env);
261      return NULL;
262    }
263
264    mid = methodIdFromClass(className, "<init>", ctorSignature, 
265                            INSTANCE, env);
266    if (mid == NULL) {
267        (*env)->ExceptionDescribe(env);
268        return NULL;
269    } 
270    va_start(args, ctorSignature);
271    jobj = (*env)->NewObjectV(env, cls, mid, args);
272    va_end(args);
273    jthr = (*env)->ExceptionOccurred(env);
274    if (jthr != NULL) {
275        if (exc != NULL)
276            *exc = jthr;
277        else
278            (*env)->ExceptionDescribe(env);
279    }
280    return jobj;
281}
282
283
284
285
286jmethodID methodIdFromClass(const char *className, const char *methName, 
287                            const char *methSignature, MethType methType, 
288                            JNIEnv *env)
289{
290    jclass cls = globalClassReference(className, env);
291    if (cls == NULL) {
292      fprintf(stderr, "could not find class %s\n", className);
293      return NULL;
294    }
295
296    jmethodID mid = 0;
297    if (!validateMethodType(methType)) {
298      fprintf(stderr, "invalid method type\n");
299      return NULL;
300    }
301
302    if (methType == STATIC) {
303        mid = (*env)->GetStaticMethodID(env, cls, methName, methSignature);
304    }
305    else if (methType == INSTANCE) {
306        mid = (*env)->GetMethodID(env, cls, methName, methSignature);
307    }
308    if (mid == NULL) {
309      fprintf(stderr, "could not find method %s from class %s with signature %s\n",methName, className, methSignature);
310    }
311    return mid;
312}
313
314
315jclass globalClassReference(const char *className, JNIEnv *env)
316{
317    jclass clsLocalRef;
318    jclass cls = searchEntryFromTable(className);
319    if (cls) {
320        return cls; 
321    }
322
323    clsLocalRef = (*env)->FindClass(env,className);
324    if (clsLocalRef == NULL) {
325        (*env)->ExceptionDescribe(env);
326        return NULL;
327    }
328    cls = (*env)->NewGlobalRef(env, clsLocalRef);
329    if (cls == NULL) {
330        (*env)->ExceptionDescribe(env);
331        return NULL;
332    }
333    (*env)->DeleteLocalRef(env, clsLocalRef);
334    insertEntryIntoTable(className, cls);
335    return cls;
336}
337
338
339char *classNameOfObject(jobject jobj, JNIEnv *env) {
340    jclass cls, clsClass;
341    jmethodID mid;
342    jstring str;
343    const char *cstr;
344    char *newstr;
345
346    cls = (*env)->GetObjectClass(env, jobj);
347    if (cls == NULL) {
348        (*env)->ExceptionDescribe(env);
349        return NULL;
350    }
351    clsClass = (*env)->FindClass(env, "java/lang/Class");
352    if (clsClass == NULL) {
353        (*env)->ExceptionDescribe(env);
354        return NULL;
355    }
356    mid = (*env)->GetMethodID(env, clsClass, "getName", "()Ljava/lang/String;");
357    if (mid == NULL) {
358        (*env)->ExceptionDescribe(env);
359        return NULL;
360    }
361    str = (*env)->CallObjectMethod(env, cls, mid);
362    if (str == NULL) {
363        (*env)->ExceptionDescribe(env);
364        return NULL;
365    }
366
367    cstr = (*env)->GetStringUTFChars(env, str, NULL);
368    newstr = strdup(cstr);
369    (*env)->ReleaseStringUTFChars(env, str, cstr);
370    if (newstr == NULL) {
371        perror("classNameOfObject: strdup");
372        return NULL;
373    }
374    return newstr;
375}
376
377
378
379
380/**
381 * getJNIEnv: A helper function to get the JNIEnv* for the given thread.
382 * If no JVM exists, then one will be created. JVM command line arguments
383 * are obtained from the LIBHDFS_OPTS environment variable.
384 *
385 * @param: None.
386 * @return The JNIEnv* corresponding to the thread.
387 */
388JNIEnv* getJNIEnv(void)
389{
390
391    const jsize vmBufLength = 1;
392    JavaVM* vmBuf[vmBufLength]; 
393    JNIEnv *env;
394    jint rv = 0; 
395    jint noVMs = 0;
396
397    // Only the first thread should create the JVM. The other trheads should
398    // just use the JVM created by the first thread.
399    LOCK_JVM_MUTEX();
400
401    rv = JNI_GetCreatedJavaVMs(&(vmBuf[0]), vmBufLength, &noVMs);
402    if (rv != 0) {
403        fprintf(stderr, "JNI_GetCreatedJavaVMs failed with error: %d\n", rv);
404        UNLOCK_JVM_MUTEX();
405        return NULL;
406    }
407
408    if (noVMs == 0) {
409        //Get the environment variables for initializing the JVM
410        char *hadoopClassPath = getenv("CLASSPATH");
411        if (hadoopClassPath == NULL) {
412            fprintf(stderr, "Environment variable CLASSPATH not set!\n");
413            UNLOCK_JVM_MUTEX();
414            return NULL;
415        } 
416        char *hadoopClassPathVMArg = "-Djava.class.path=";
417        size_t optHadoopClassPathLen = strlen(hadoopClassPath) + 
418          strlen(hadoopClassPathVMArg) + 1;
419        char *optHadoopClassPath = malloc(sizeof(char)*optHadoopClassPathLen);
420        snprintf(optHadoopClassPath, optHadoopClassPathLen,
421                "%s%s", hadoopClassPathVMArg, hadoopClassPath);
422
423        int noArgs = 1;
424        //determine how many arguments were passed as LIBHDFS_OPTS env var
425        char *hadoopJvmArgs = getenv("LIBHDFS_OPTS");
426        char jvmArgDelims[] = " ";
427        if (hadoopJvmArgs != NULL)  {
428                char *result = NULL;
429                result = strtok( hadoopJvmArgs, jvmArgDelims );
430                while ( result != NULL ) {
431                        noArgs++;
432                        result = strtok( NULL, jvmArgDelims);
433                }
434        }
435        JavaVMOption options[noArgs];
436        options[0].optionString = optHadoopClassPath;
437                //fill in any specified arguments
438        if (hadoopJvmArgs != NULL)  {
439            char *result = NULL;
440            result = strtok( hadoopJvmArgs, jvmArgDelims );     
441            int argNum = 1;
442            for (;argNum < noArgs ; argNum++) {
443                options[argNum].optionString = result; //optHadoopArg;
444            }
445        }
446
447        //Create the VM
448        JavaVMInitArgs vm_args;
449        JavaVM *vm;
450        vm_args.version = JNI_VERSION_1_2;
451        vm_args.options = options;
452        vm_args.nOptions = noArgs; 
453        vm_args.ignoreUnrecognized = 1;
454
455        rv = JNI_CreateJavaVM(&vm, (void*)&env, &vm_args);
456        if (rv != 0) {
457            fprintf(stderr, "Call to JNI_CreateJavaVM failed "
458                    "with error: %d\n", rv);
459            UNLOCK_JVM_MUTEX();
460            return NULL;
461        }
462
463        free(optHadoopClassPath);
464    }
465    else {
466        //Attach this thread to the VM
467        JavaVM* vm = vmBuf[0];
468        rv = (*vm)->AttachCurrentThread(vm, (void*)&env, 0);
469        if (rv != 0) {
470            fprintf(stderr, "Call to AttachCurrentThread "
471                    "failed with error: %d\n", rv);
472            UNLOCK_JVM_MUTEX();
473            return NULL;
474        }
475    }
476    UNLOCK_JVM_MUTEX();
477
478    return env;
479}
Note: See TracBrowser for help on using the repository browser.