223 lines
5.9 KiB
C++
223 lines
5.9 KiB
C++
//
|
|
// jnibinding.c
|
|
// libionu-xcode
|
|
//
|
|
// Created by Tim Beres on 9/7/12.
|
|
// Copyright (c) 2012 Tim Beres. All rights reserved.
|
|
//
|
|
|
|
#include "K2jnibinding.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef WIN32
|
|
#include <stdbool.h>
|
|
#endif
|
|
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
#include "platform_binding.h"
|
|
|
|
// we can't use ourself to debug ourself
|
|
#undef SLDEBUG
|
|
#undef DEBUG // comment out for debugging
|
|
//#define DEBUG 1
|
|
|
|
#if defined(DEBUG)
|
|
#if defined(ANDROID)
|
|
#include <android/log.h>
|
|
#define SLDEBUG(...) __android_log_print(ANDROID_LOG_DEBUG, "[K2LOG]", __VA_ARGS__)
|
|
#else
|
|
#define SLDEBUG(...) fputs("[K2LOG]",stdout);printf(__VA_ARGS__);fflush(stdout);
|
|
#endif
|
|
#else
|
|
#define SLDEBUG(...)
|
|
#endif
|
|
|
|
static JavaVM *_k2jvm;
|
|
static jclass _k2cbClass;
|
|
static jmethodID _k2cbMeth;
|
|
|
|
/**
|
|
* This is the callback supplied to K2_Init.
|
|
* It's purpose is to send the info back into the JVM.
|
|
*/
|
|
static void _k2onMessage(const char* info)
|
|
{
|
|
SLDEBUG("_k2onMessage %s\n", info);
|
|
|
|
JNIEnv *env;
|
|
|
|
#if defined(ANDROID)
|
|
jint rs = _k2jvm->AttachCurrentThread(&env, NULL);
|
|
#else
|
|
jint rs = _k2jvm->AttachCurrentThread(reinterpret_cast<void **>(&env), NULL);
|
|
#endif
|
|
assert (rs == JNI_OK);
|
|
|
|
if (_k2cbMeth != 0){
|
|
jstring cbInfo = env->NewStringUTF(info);
|
|
SLDEBUG("_k2onMessage invoking cbMeth %p\n", _k2cbMeth);
|
|
env->CallStaticVoidMethod(_k2cbClass, _k2cbMeth, cbInfo, 0);
|
|
} else {
|
|
SLDEBUG("_k2onMessage drop message; null callback\n");
|
|
}
|
|
SLDEBUG("_k2onMessage leave: %s\n", info);
|
|
|
|
_k2jvm->DetachCurrentThread();
|
|
|
|
}
|
|
|
|
/**
|
|
* Using the global ref _k2cbClass, look for a given method name and save ref in _k2cbMeth.
|
|
* We assume this MUST succeed or its a coding error.
|
|
*/
|
|
bool checkCallbackMethod(JNIEnv *env, const char* meth){
|
|
_k2cbMeth = env->GetStaticMethodID(_k2cbClass, meth, "(Ljava/lang/String;)V");
|
|
SLDEBUG("checkCallback have method %p\n", _k2cbMeth);
|
|
if (_k2cbMeth != NULL){
|
|
// leads to: Invalid indirect reference 0x43955f98 in decodeIndirectRef
|
|
// _k2cbMeth = env->NewGlobalRef(env, _k2cbMeth);
|
|
}
|
|
return _k2cbMeth != NULL;
|
|
}
|
|
|
|
/**
|
|
* Try to find given 'clazz' name which is allowed not to be found.
|
|
* If found set global ref.
|
|
*/
|
|
bool checkCallback(JNIEnv *env, const char* clazz, const char* meth){
|
|
SLDEBUG("checkCallback using JNIEnv %p look for class %s\n", env, clazz);
|
|
|
|
_k2cbClass = env->FindClass(clazz);
|
|
SLDEBUG("checkCallback have class %p\n", _k2cbClass);
|
|
if (!_k2cbClass){
|
|
if (env->ExceptionCheck()) {
|
|
SLDEBUG("Clear exception\n");
|
|
env->ExceptionClear();
|
|
}
|
|
return false;
|
|
}
|
|
// Android GC moves sh*t around!!!
|
|
_k2cbClass = static_cast<jclass>(env->NewGlobalRef(_k2cbClass));
|
|
return checkCallbackMethod(env, meth);
|
|
}
|
|
|
|
/**
|
|
* Try to setup to use SyncAndMessageDispatch as the handler in JVM.
|
|
* Since CG also wants to pretend to be a client, this will gracefully fail and set refs
|
|
* to NULL for that particular case.
|
|
*/
|
|
jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
|
|
{
|
|
JNIEnv *env;
|
|
|
|
SLDEBUG("JNI_OnLoad\n");
|
|
|
|
vm->GetEnv (reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
|
|
//if (!checkCallback(env, "com/sequencelogic/cgsl/DataManager", "k2dataReceived"))
|
|
{
|
|
checkCallback(env, "com/sequencelogic/ijw/client/SyncAndMessageDispatch", "k2dataReceived");
|
|
}
|
|
return JNI_VERSION_1_6;
|
|
}
|
|
|
|
/**
|
|
* Initialize passing optional class loader object and the callback class
|
|
* which will be SyncAndMessageDispatch or DataManager. Due to Tomcat class loading
|
|
* issues, this may work where the OnLoad will fail.
|
|
*/
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_initialize(JNIEnv *env, jobject obj, jobject webCL, jstring callbackClassNameDotted, jstring hosts, jstring urn)
|
|
{
|
|
const char* chost = env->GetStringUTFChars(hosts, 0);
|
|
const char* curn = env->GetStringUTFChars(urn, 0);
|
|
|
|
SLDEBUG("K2Client_initialize\n");
|
|
if (_k2cbMeth == 0 && webCL != 0){
|
|
SLDEBUG("Did not find callback class/method during onLoad; trying with class loader\n");
|
|
jclass classLoaderClass = env->GetObjectClass(webCL);
|
|
jmethodID loadClassMethod = env->GetMethodID(classLoaderClass,
|
|
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
// This needs dots because it's the arg for Java
|
|
_k2cbClass = static_cast<jclass>(env->CallObjectMethod(webCL, loadClassMethod, callbackClassNameDotted));
|
|
SLDEBUG("_k2cbClass have class %p\n", _k2cbClass);
|
|
if (env->ExceptionCheck()) {
|
|
SLDEBUG("Clear exception\n");
|
|
env->ExceptionClear();
|
|
} else {
|
|
_k2cbClass = static_cast<jclass>(env->NewGlobalRef(_k2cbClass));
|
|
checkCallbackMethod(env, "k2dataReceived");
|
|
}
|
|
}
|
|
|
|
jint rs = env->GetJavaVM(&_k2jvm);
|
|
assert (rs == JNI_OK);
|
|
|
|
// @todo how to log this
|
|
SLDEBUG("Java_com_sequencelogic_K2Client_initialize %s %s\n", chost, curn);
|
|
|
|
K2_Start
|
|
(
|
|
curn,
|
|
chost,
|
|
_k2onMessage
|
|
);
|
|
|
|
env->ReleaseStringUTFChars(urn, chost);
|
|
env->ReleaseStringUTFChars(urn, curn);
|
|
}
|
|
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_login(JNIEnv *env, jobject obj)
|
|
{
|
|
SLDEBUG("login/restart");
|
|
K2_Restart();
|
|
}
|
|
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_logout(JNIEnv *env, jobject obj)
|
|
{
|
|
K2_Stop();
|
|
}
|
|
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_shutdown(JNIEnv *env, jobject obj)
|
|
{
|
|
K2_Stop();
|
|
}
|
|
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_pollDB(JNIEnv *env, jobject obj)
|
|
{
|
|
K2_Poll_DB();
|
|
}
|
|
|
|
jstring JNICALL
|
|
Java_com_sequencelogic_K2Client_statistics(JNIEnv *env, jobject obj)
|
|
{
|
|
static const int SBUFSZ = 4096;
|
|
char buf[SBUFSZ];
|
|
jstring result = NULL;
|
|
*buf = 0;
|
|
K2_GetStats(buf, SBUFSZ);
|
|
|
|
//printf("Java_com_sequencelogic_K2Client_statistics result %d : %s\n", b, buf);
|
|
if (*buf){
|
|
result = env->NewStringUTF(buf);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void JNICALL
|
|
Java_com_sequencelogic_K2Client_statusSelect(JNIEnv *env, jobject obj, jstring offices)
|
|
{
|
|
const char* coffices = env->GetStringUTFChars(offices, 0);
|
|
K2_StatusSelect(coffices);
|
|
env->ReleaseStringUTFChars(offices, coffices);
|
|
}
|