diff --git a/src/Test.java b/src/Test.java deleted file mode 100644 index 0fcdc57..0000000 --- a/src/Test.java +++ /dev/null @@ -1,13 +0,0 @@ -import org.pEp.jniadapter.*; - -public class Test { - public static void main(String[] args) { - try (Engine pEp = new Engine()) { - // using pEp engine - } - catch (pEpException e) { - - } - } -} - diff --git a/src/gen_cpp_Message.ysl2 b/src/gen_cpp_Message.ysl2 index 342ddb7..c7160c7 100644 --- a/src/gen_cpp_Message.ysl2 +++ b/src/gen_cpp_Message.ysl2 @@ -3,7 +3,7 @@ include yslt.yml2 tstylesheet { include ./types_c.ysl2 - template "/namespace[@name='pEp']" apply "struct|interface", 0; + template "/namespace[@name='pEp']" apply "struct", 0; template "struct" { const "jname" call "CamelCase" with "text", "@name"; @@ -11,6 +11,7 @@ tstylesheet { document("org_pEp_jniadapter_{$jname}.cc", "text") || #include + #include #include #include #include @@ -18,74 +19,112 @@ tstylesheet { #include "jniutils.hh" #include "org_pEp_jniadapter_«$jname».h" + using namespace std; + + namespace pEp { + namespace JNIAdapter { + static ::«@name» *«@name»_ptr(JNIEnv *env, jobject me) { + jfieldID handle; + + try { + handle = getFieldID(env, "org/pEp/jniadapter/«$jname»", "handle", "J"); + } + catch (std::exception& ex) { + assert(0); + return NULL; + } + + return (::«@name» *) (intptr_t) (int64_t) env->GetLongField(me, handle); + } + }; + }; + + extern "C" { + using namespace pEp::JNIAdapter; JNIEXPORT jlong JNICALL Java_org_pEp_jniadapter_«$jname»_init(JNIEnv *env, jobject obj) { ::«@name» * _obj = ::new_«@name»(PEP_dir_incoming); - // BUG: test for out of memory missing + if (!_obj) { + outOfMemory(env); + return (jlong) 0; + } return (jlong) (int64_t) (intptr_t) _obj; } JNIEXPORT void JNICALL Java_org_pEp_jniadapter_«$jname»_release(JNIEnv *env, jobject obj, jlong value) { - ::«@name» *_obj = (::«@name» *) (intptr_t) (int64_t) value; - ::free_«@name»(_obj); - } - - static ::«@name» *ptr(JNIEnv *env, jobject me) { - jfieldID handle; - - try { - handle = getFieldID(env, "org/pEp/jniadapter/«$jname»", "handle", "J"); - } - catch (std::exception& ex) { - assert(0); - return NULL; + if (value) { + ::«@name» *_obj = (::«@name» *) (intptr_t) (int64_t) value; + ::free_«@name»(_obj); } - - return (::«@name» *) (intptr_t) (int64_t) env->GetLongField(me, handle); } - `` apply "*[name(.)!='enum']", 0, mode=entry with "class" call "CamelCase" with "text", "@name"; - || - } - - template "interface" { - const "jname" call "CamelCase" with "text", "@name"; - - document("org_pEp_jniadapter_{$jname}.cc", "text") - || - #include "org_pEp_jniadapter_«$jname».h" + `` apply "*[name(.)!='enum']", 0, mode=entry with "name", "@name", with "class" call "CamelCase" with "text", "@name"; + } // extern "C" || } template "*", mode=entry { + param "name"; param "class"; - const "_class" call "lcase" with "text", "$class"; const "ctype" call "toC" with "type", "name(.)"; const "jname" call "CamelCase" with "text", "name(*[1])"; const "cname" call "lcase" with "text", "name(*[1])"; + const "type", "name(.)"; || - JNIEXPORT jobject JNICALL + JNIEXPORT `call "jni_type" with "type", "name(.)"` JNICALL Java_org_pEp_jniadapter_«$class»_get«$jname»(JNIEnv *env, jobject obj) { - «$_class» *_obj = ptr(env, obj); - jobject result = NULL; - - _obj->«$cname»; - return result; + «$name» *_obj = «$name»_ptr(env, obj); + || + choose { + when "../enum[@name=$type]" + |> return (jint) _obj->«$cname»; + otherwise + |> return from_«$type»(env, _obj->«$cname»); + } + || } JNIEXPORT void JNICALL - Java_org_pEp_jniadapter_Message_set«$jname»(JNIEnv *env, jobject obj, jobject value) { - «$_class» *_obj = ptr(env, obj); - «$ctype» *_value; - _obj->«$cname»; + Java_org_pEp_jniadapter_Message_set«$jname»(JNIEnv *env, jobject obj, `call "jni_type" with "type", "name(.)"` value) { + «$name» *_obj = «$name»_ptr(env, obj); + || + choose { + when "../enum[@name=$type]" + |> _obj->«$cname» = («$ctype») (int) value; + when "$type = 'string'" { + |> free(_obj->«$cname»); + |> _obj->«$cname» = to_«$type»(env, value); + } + otherwise { + const "free" choose { + when "$ctype = 'pEp_identity'" > identity + when "contains($ctype, '_t')" value "substring-before($ctype, '_t')"; + otherwise value "$ctype"; + } + + |> free_«$free»(_obj->«$cname»); + |> _obj->«$cname» = to_«$type»(env, value); + } + } + || } || } + + function "jni_type" { + param "type"; + + choose { + when "../enum[@name=$type]" > jint + when "$type = 'string'" > jbyteArray + otherwise > jobject + } + } } diff --git a/src/jniutils.cc b/src/jniutils.cc index fda43df..5113bbf 100644 --- a/src/jniutils.cc +++ b/src/jniutils.cc @@ -7,24 +7,31 @@ namespace pEp { namespace JNIAdapter { - jfieldID getFieldID( - JNIEnv *env, - const char *classname, - const char *fieldname, - const char *signature - ) + jclass findClass(JNIEnv *env, const char *classname) { - jclass engine = env->FindClass(classname); - assert(engine); + jclass clazz = env->FindClass(classname); + assert(clazz); - if (engine == NULL) { + if (clazz == NULL) { jclass ex = env->FindClass("java/lang/NoClassDefFoundError"); assert(ex); env->ThrowNew(ex, classname); throw std::bad_cast(); } + + return clazz; + } - jfieldID field = env->GetFieldID(engine, fieldname, signature); + jfieldID getFieldID( + JNIEnv *env, + const char *classname, + const char *fieldname, + const char *signature + ) + { + jclass clazz = findClass(env, classname); + + jfieldID field = env->GetFieldID(clazz, fieldname, signature); assert(field); if (field == NULL) { @@ -36,6 +43,75 @@ namespace pEp { return field; } + + jlong callLongMethod( + JNIEnv *env, + jobject obj, + const char *methodname + ) + { + jclass clazz = env->GetObjectClass(obj); + assert(clazz); + + jmethodID method = env->GetMethodID(clazz, methodname, "()J"); + if (method == NULL) { + jclass ex = env->FindClass("java/lang/NoSuchMethodError"); + assert(ex); + env->ThrowNew(ex, methodname); + throw std::invalid_argument(std::string(methodname)); + } + + return env->CallLongMethod(obj, method); + } + + jint outOfMemory(JNIEnv *env) + { + jclass ex; + const char *ex_name = "java/lang/OutOfMemoryError"; + + ex = env->FindClass(ex_name); + assert(ex); + return env->ThrowNew(ex, ex_name); + } + + jbyteArray from_string(JNIEnv *env, const char *str) + { + if (str && str[0]) { + bool isCopy; + jbyteArray _str = NewByteArray(env, strlen(str)); + jbyte *b = GetByteArrayElements(env, str, &isCopy); + strcpy((char *)b, str); + ReleaseByteArrayElements(env, str, b, 0); + return _str; + } + else { + return NewByteArray(env, 0); + } + } + + char *to_string(JNIEnv *env, jbyteArray str) + { + bool isCopy; + jbyte *b = GetByteArrayElements(env, str, &isCopy); + char *_str = strndup((char *)b, (size_t)GetArrayLength(env, str)); + ReleaseByteArrayElements(env, str, b, JNI_ABORT); + return _str; + } + + jobject from_timestamp(JNIEnv *env, timestamp *ts) + { + time_t t = timegm(ts); + jclass clazz = findClass(env, "java/util/Date"); + jmethodID constructor = env->GetMethodID(clazz, "", "(J)V"); + assert(constructor); + return env->NewObject(clazz, constructor, (jlong) t); + } + + timestamp *to_timestamp(JNIEnv *env, jobject date) + { + time_t t = (time_t) callLongMethod(env, date, "getTime"); + return new_timestamp(t); + } }; }; diff --git a/src/jniutils.hh b/src/jniutils.hh index 34de343..a672c8d 100644 --- a/src/jniutils.hh +++ b/src/jniutils.hh @@ -4,12 +4,43 @@ namespace pEp { namespace JNIAdapter { + jclass findClass(JNIEnv *env, const char *classname); + jfieldID getFieldID( JNIEnv *env, const char *classname, const char *fieldname, const char *signature ); + + jlong callLongMethod( + JNIEnv *env, + jobject obj, + const char *methodname + ); + + jint outOfMemory(JNIEnv *env); + + jbyteArray from_string(JNIEnv *env, const char *str); + char *to_string(JNIEnv *env, jbyteArray str); + + jobject from_stringlist(JNIEnv *env, stringlist_t *sl); + stringlist_t *to_stringlist(JNIEnv *env, jobject sl); + + jobject from_stringpairlist(JNIEnv *env, stringpair_list_t *sl); + stringpair_list_t *to_stringpairlist(JNIEnv *env, jobject sl); + + jobject from_timestamp(JNIEnv *env, timestamp *ts); + timestamp *to_timestamp(JNIEnv *env, jobject date); + + jobject from_identity(JNIEnv *env, pEp_identity *ident); + pEp_identity *to_identity(JNIEnv *env, jobject ident); + + jobject from_identitylist(JNIEnv *env, identity_list *il); + identity_list *to_identitylist(JNIEnv *env, jobject il); + + jobject from_bloblist(JNIEnv *env, bloblist_t *bl); + bloblist_t *to_bloblist(JNIEnv *env, jobject bl); }; };