JavaVoidMethodCaller.h

Go to the documentation of this file.
00001 /*
00002  *  BEEN: Benchmarking Environment
00003  *  ==============================
00004  *
00005  *  File author: Branislav Repcek
00006  *
00007  *  GNU Lesser General Public License Version 2.1
00008  *  ---------------------------------------------
00009  *  Copyright (C) 2004-2006 Distributed Systems Research Group,
00010  *  Faculty of Mathematics and Physics, Charles University in Prague
00011  *
00012  *  This library is free software; you can redistribute it and/or
00013  *  modify it under the terms of the GNU Lesser General Public
00014  *  License version 2.1, as published by the Free Software Foundation.
00015  *
00016  *  This library is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Lesser General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU Lesser General Public
00022  *  License along with this library; if not, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00024  *  MA  02111-1307  USA
00025  */
00026 
00034 #ifndef JAVA_VOID_METHOD_CALLER
00035 #define JAVA_VOID_METHOD_CALLER
00036 
00037 // Disable warnings about deprecated "unsecure" functions from STL in Visual Studio 2005+.
00038 #if _MSC_VER >= 1400
00039 #define _SCL_SECURE_NO_DEPRECATE 1
00040 #endif
00041 
00042 #include <jni.h>
00043 #include <vector>
00044 #include <algorithm>
00045 #include "String.h"
00046 #include "TypeList.h"
00047 #include "CompileTimeCheck.h"
00048 
00049 namespace lm
00050 {
00067     class JavaVoidMethodCaller
00068     {
00069     public:
00070 
00071         /* Let the template meta-programming madness begin! 
00072          * 
00073          * This is also warning for those that are brave and try to read and understand this code.
00074          */
00075 
00084         JavaVoidMethodCaller(JNIEnv *env, jclass java_class, jobject java_object, bool swallow_java_exceptions = true) :
00085         jni_env(env),
00086         target_class(java_class),
00087         object(java_object),
00088         swallow_exceptions(swallow_java_exceptions)
00089         {
00090         }
00091 
00094         ~JavaVoidMethodCaller(void)
00095         {
00096         }
00097 
00107         bool Call(const char *method_name, const char *method_signature)
00108         {
00109             jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00110 
00111             if (!method_id)
00112             {
00113                 return false;
00114             }
00115 
00116             jni_env->CallVoidMethod(object, method_id);
00117 
00118             if (jni_env->ExceptionCheck())
00119             {
00120                 if (swallow_exceptions)
00121                 {
00122                     jni_env->ExceptionClear();
00123                 }
00124                 return false;
00125             }
00126 
00127             return true;
00128         }
00129 
00142         template< typename T1 > 
00143         bool Call(const char *method_name, const char *method_signature, T1 param_1)
00144         {
00145             const int type_index = ::tl::IndexOf< JavaTypes, T1 >::value;
00146 
00147             COMPILE_TIME_CHECK(type_index >= 0, Parameter_type_is_not_supported);
00148 
00149             jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00150 
00151             if (!method_id)
00152             {
00153                 return false;
00154             }
00155 
00156             jni_env->CallVoidMethod(object, method_id, param_1);
00157 
00158             if (jni_env->ExceptionCheck())
00159             {
00160                 if (swallow_exceptions)
00161                 {
00162                     jni_env->ExceptionClear();
00163                 }
00164                 return false;
00165             }
00166 
00167             return true;
00168         }
00169 
00185         template< typename T1, typename T2 > 
00186         bool Call(const char *method_name, const char *method_signature, T1 param_1, T2 param_2)
00187         {
00188             const int type_index_1 = ::tl::IndexOf< JavaTypes, T1 >::value;
00189             const int type_index_2 = ::tl::IndexOf< JavaTypes, T2 >::value;
00190 
00191             COMPILE_TIME_CHECK(type_index_1 >= 0, First_parameters_type_is_not_supported);
00192             COMPILE_TIME_CHECK(type_index_2 >= 0, Second_parameters_type_is_not_supported);
00193 
00194             jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00195 
00196             if (!method_id)
00197             {
00198                 return false;
00199             }
00200 
00201             jni_env->CallVoidMethod(object, method_id, param_1, param_2);
00202 
00203             if (jni_env->ExceptionCheck())
00204             {
00205                 if (swallow_exceptions)
00206                 {
00207                     jni_env->ExceptionClear();
00208                 }
00209                 return false;
00210             }
00211 
00212             return true;
00213         }
00214 
00227         template< typename T1 >
00228         bool Call(const char *method_name, 
00229                   const char *method_signature, 
00230                   const std::vector< T1 > &param_1)
00231         {
00232             const int type_index = ::tl::IndexOf< JavaTypes, T1 >::value;
00233 
00234             // Test of type is valid and it is not void
00235             COMPILE_TIME_CHECK(type_index >= 1, Parameter_type_is_not_supported);
00236 
00237             jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00238 
00239             if (!method_id)
00240             {
00241                 return false;
00242             }
00243 
00244             typedef typename ::tl::Get< ArrayMethodAdapters, type_index >::Result AdapterType;
00245 
00246             bool result = true;
00247             AdapterType adapter(jni_env);
00248 
00249             typename AdapterType::JavaType java_array = adapter.NewArray(static_cast< jsize >(param_1.size()));
00250 
00251             // Copy data from vector to the Java array.
00252             T1 *array_data = new T1[param_1.size()];
00253 
00254             std::copy(param_1.begin(), param_1.end(), array_data);
00255 
00256             adapter.SetArrayRegion(java_array, 0, static_cast< jsize >(param_1.size()), array_data);
00257 
00258             jni_env->CallVoidMethod(object, method_id, java_array);
00259 
00260             if (jni_env->ExceptionCheck())
00261             {
00262                 if (swallow_exceptions)
00263                 {
00264                     jni_env->ExceptionClear();
00265                 }
00266                 result = false;
00267             }
00268 
00269             adapter.DeleteArray(java_array, array_data); // <- so stupid, I want to free array without copying crap around
00270             //delete []array_data;
00271 
00272             return result;
00273         }
00274 
00290         template< typename T1, typename T2 > 
00291         bool Call(const char *method_name, 
00292                   const char *method_signature, 
00293                   const std::vector< T1 > &param_1,
00294                   const std::vector< T2 > &param_2)
00295         {
00296             const int type_index_1 = ::tl::IndexOf< JavaTypes, T1 >::value;
00297             const int type_index_2 = ::tl::IndexOf< JavaTypes, T2 >::value;
00298 
00299             COMPILE_TIME_CHECK(type_index_1 >= 1, Parameter_type_is_not_supported);
00300             COMPILE_TIME_CHECK(type_index_2 >= 1, Parameter_type_is_not_supported);
00301 
00302             jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00303 
00304             if (!method_id)
00305             {
00306                 return false;
00307             }
00308 
00309             typedef typename ::tl::Get< ArrayMethodAdapters, type_index_1 >::Result AdapterType_1;
00310             typedef typename ::tl::Get< ArrayMethodAdapters, type_index_2 >::Result AdapterType_2;
00311 
00312             bool result = true;
00313 
00314             AdapterType_1 adapter_1(jni_env);
00315             AdapterType_2 adapter_2(jni_env);
00316 
00317             typename AdapterType_1::JavaType java_array_1 = adapter_1.NewArray(static_cast< jsize >(param_1.size()));
00318             typename AdapterType_2::JavaType java_array_2 = adapter_2.NewArray(static_cast< jsize >(param_2.size()));
00319 
00320             // Copy data from first vector to the first Java array.
00321             T1 *array_data_1 = new T1[param_1.size()];
00322 
00323             std::copy(param_1.begin(), param_1.end(), array_data_1);
00324             adapter_1.SetArrayRegion(java_array_1, 0, static_cast< jsize >(param_1.size()), array_data_1);
00325 
00326             // Copy data from second vector to the second Java array.
00327             T2 *array_data_2 = new T2[param_1.size()];
00328 
00329             std::copy(param_2.begin(), param_2.end(), array_data_2);
00330             adapter_2.SetArrayRegion(java_array_2, 0, static_cast< jsize >(param_2.size()), array_data_2);
00331 
00332             jni_env->CallVoidMethod(object, method_id, java_array_1, java_array_2);
00333 
00334             if (jni_env->ExceptionCheck())
00335             {
00336                 if (swallow_exceptions)
00337                 {
00338                     jni_env->ExceptionClear();
00339                 }
00340                 result = false;
00341             }
00342 
00343             adapter_1.DeleteArray(java_array_1, array_data_1);
00344             //delete []array_data_1;
00345 
00346             adapter_2.DeleteArray(java_array_2, array_data_2);
00347             //delete []array_data_2;
00348 
00349             return result;
00350         }
00351 
00357         bool GetSwallowExceptions(void)
00358         {
00359             return swallow_exceptions;
00360         }
00361 
00369         bool SetSwallowException(bool se)
00370         {
00371             bool ose = swallow_exceptions;
00372 
00373             swallow_exceptions = se;
00374 
00375             return ose;
00376         }
00377 
00378     private:
00380         JNIEnv  *jni_env;
00381 
00383         jclass  target_class;
00384 
00386         jobject object;
00387 
00389         bool    swallow_exceptions;
00390 
00395         typedef CREATE_TYPE_LIST_09(void, 
00396                                     jboolean, 
00397                                     jbyte, 
00398                                     jchar, 
00399                                     jshort, 
00400                                     jint, 
00401                                     jlong, 
00402                                     jfloat, 
00403                                     jdouble) JavaTypes;
00404 
00409         typedef CREATE_TYPE_LIST_09(void, 
00410                                     jbooleanArray, 
00411                                     jbyteArray, 
00412                                     jcharArray, 
00413                                     jshortArray, 
00414                                     jintArray, 
00415                                     jlongArray, 
00416                                     jfloatArray, 
00417                                     jdoubleArray) JavaArrayTypes;
00418 
00419 
00422 #define CREATE_ARRAY_METHOD_ADAPTER_CLASS(NativeType_, middle_name)                                                                 \
00423         class ArrayMethodAdapter_##middle_name                                                                                      \
00424         {                                                                                                                           \
00425         public:                                                                                                                     \
00426             typedef NativeType_ NativeType;                                                                                         \
00427             typedef ::tl::Get< JavaArrayTypes, ::tl::IndexOf< JavaTypes, NativeType >::value >::Result JavaType;                    \
00428             ArrayMethodAdapter_##middle_name(JNIEnv *env) :                                                                         \
00429             jni_env(env)                                                                                                            \
00430             {                                                                                                                       \
00431             }                                                                                                                       \
00432             ~ArrayMethodAdapter_##middle_name(void)                                                                                 \
00433             {                                                                                                                       \
00434             }                                                                                                                       \
00435             JavaType NewArray(jsize size)                                                                                           \
00436             {                                                                                                                       \
00437                 return jni_env->New##middle_name##Array(size);                                                                      \
00438             }                                                                                                                       \
00439             void DeleteArray(JavaType java_array, NativeType *elements)                                                             \
00440             {                                                                                                                       \
00441                 jni_env->Release##middle_name##ArrayElements(java_array, elements, 0);                                              \
00442             }                                                                                                                       \
00443             void GetArrayRegion(JavaType java_array, jsize start, jsize len, NativeType *buffer)                                    \
00444             {                                                                                                                       \
00445                 jni_env->Get##middle_name##ArrayRegion(java_array, start, len, buffer);                                             \
00446             }                                                                                                                       \
00447             void SetArrayRegion(JavaType java_array, jsize start, jsize len, NativeType *buffer)                                    \
00448             {                                                                                                                       \
00449                 jni_env->Set##middle_name##ArrayRegion(java_array, start, len, buffer);                                             \
00450             }                                                                                                                       \
00451             NativeType *GetArrayElements(JavaType java_array)                                                                       \
00452             {                                                                                                                       \
00453                 return jni_env->Get##middle_name##ArrayElements(java_array, NULL);                                                  \
00454             }                                                                                                                       \
00455             size_t GetArrayLength(jarray java_array)                                                                                \
00456             {                                                                                                                       \
00457                 return jni_env->GetArrayLength(java_array);                                                                         \
00458             }                                                                                                                       \
00459         private:                                                                                                                    \
00460             JNIEnv  *jni_env;                                                                                                       \
00461         };
00462 
00467         class ArrayMethodAdapter_String
00468         {
00469         public:
00471             typedef jobjectArray JavaType;
00472 
00474             typedef jstring NativeType;
00475 
00480             ArrayMethodAdapter_String(JNIEnv *env) :
00481             jni_env(env)
00482             {
00483                 // Find string class from (java.lang.String).
00484                 string_class = jni_env->FindClass("java/lang/String");
00485             }
00486 
00489             ~ArrayMethodAdapter_String(void)
00490             {
00491             }
00492 
00499             jobjectArray NewArray(jsize size)
00500             {
00501                 return jni_env->NewObjectArray(size, string_class, NULL);
00502             }
00503 
00510             void SetElement(jobjectArray java_array, size_t index, const String &value)
00511             {
00512 #ifdef WIN32
00513                 // Use UNICODE strings on Win
00514                 jstring new_value = jni_env->NewString((jchar *) value.c_str(), static_cast< jsize >(value.length()));
00515 #else
00516                 // ASCII elsewhere
00517                 jstring new_value = jni_env->NewStringUTF(value.c_str());
00518 #endif
00519 
00520                 jni_env->SetObjectArrayElement(java_array, static_cast< jsize >(index), new_value);
00521             }
00522 
00529             size_t GetArrayLength(jarray java_array)
00530             {
00531                 return jni_env->GetArrayLength(java_array);
00532             }
00533 
00534         private:
00535             JNIEnv  *jni_env;
00536             jclass  string_class;
00537         };
00538 
00541         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jboolean, Boolean)
00542 
00543         
00545         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jbyte, Byte)
00546 
00549         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jchar, Char)
00550 
00553         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jshort, Short)
00554 
00557         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jint, Int)
00558 
00561         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jlong, Long)
00562 
00565         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jfloat, Float)
00566 
00569         CREATE_ARRAY_METHOD_ADAPTER_CLASS(jdouble, Double)
00570 
00576         typedef CREATE_TYPE_LIST_09(void,
00577                                     ArrayMethodAdapter_Boolean,
00578                                     ArrayMethodAdapter_Byte,
00579                                     ArrayMethodAdapter_Char,
00580                                     ArrayMethodAdapter_Short,
00581                                     ArrayMethodAdapter_Int,
00582                                     ArrayMethodAdapter_Long,
00583                                     ArrayMethodAdapter_Float,
00584                                     ArrayMethodAdapter_Double) ArrayMethodAdapters;
00585     };
00586 
00601     template< >
00602     bool JavaVoidMethodCaller::Call< String >(const char *method_name, const char *method_signature, String param_1)
00603     {
00604         jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00605 
00606         if (!method_id)
00607         {
00608             return false;
00609         }
00610 
00611 #ifdef WIN32
00612         jstring str_param = jni_env->NewString((jchar *) param_1.c_str(), static_cast< jsize >(param_1.length()));
00613 #else
00614         jstring str_param = jni_env->NewStringUTF(param_1.c_str());
00615 #endif
00616 
00617         jni_env->CallVoidMethod(object, method_id, str_param);
00618 
00619         if (jni_env->ExceptionCheck())
00620         {
00621             if (swallow_exceptions)
00622             {
00623                 jni_env->ExceptionClear();
00624             }
00625             return false;
00626         }
00627 
00628         return true;
00629     }
00630 
00646     template< >
00647     bool JavaVoidMethodCaller::Call< String >(const char *method_name,
00648                                               const char *method_signature,
00649                                               const std::vector< String > &param_1)
00650     {
00651         jmethodID method_id = jni_env->GetMethodID(target_class, method_name, method_signature);
00652 
00653         if (!method_id)
00654         {
00655             return false;
00656         }
00657 
00658         ArrayMethodAdapter_String adapter(jni_env);
00659 
00660        /* Note: I have no idea if this creates memory leak or not. I was not able to find equivalent of the ReleaseXXXArrayElements
00661         * method which works for jobjectArrays. So I guess Java will do this automatically.
00662         */
00663 
00664         ArrayMethodAdapter_String::JavaType java_array = adapter.NewArray(static_cast< jsize >(param_1.size()));
00665 
00666         for (size_t i = 0; i < param_1.size(); ++i)
00667         {
00668             adapter.SetElement(java_array, i, param_1[i]);
00669         }
00670 
00671         jni_env->CallVoidMethod(object, method_id, java_array);
00672 
00673         if (jni_env->ExceptionCheck())
00674         {
00675             if (swallow_exceptions)
00676             {
00677                 jni_env->ExceptionClear();
00678             }
00679             return false;
00680         }
00681 
00682         return true;
00683     }
00684 
00685 } // namespace lm
00686 
00687 #endif

Generated on Tue Dec 19 17:43:48 2006 for Load Monitor for Linux by  doxygen 1.4.7