boinc/dcapi/java/client.c

484 lines
11 KiB
C

/** @file client.c
*
* Client-side DC-API JNI code
*
* Author: Gábor Gombás
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <dc_client.h>
#include "util.h"
/**********************************************************************
* Global variables
*/
/* Java VM handle for the callbacks */
static JavaVM *myvm;
/* Bitmask for debugging classes */
unsigned jni_debug = 0;
/**********************************************************************
* Class: hu.sztaki.lpds.dc.client.Event
*/
/* Throws: RuntimeDCException, DCException */
JNIEXPORT jstring JNICALL Java_hu_sztaki_lpds_dc_client_Event_getMessage
(JNIEnv *env, jobject this)
{
DC_ClientEvent *event;
jfieldID field;
jclass cls;
int type;
cls = (*env)->GetObjectClass(env, this);
if (!cls)
return NULL;
field = (*env)->GetFieldID(env, cls, "type", "I");
if (!field)
{
propagate_runtime(env, "Failed to look up the type field");
return NULL;
}
type = (*env)->GetIntField(env, this, field);
if (type != DC_CLIENT_MESSAGE)
{
throw_dcexc(env, DC_ERR_BADPARAM, "This is not a message event");
return NULL;
}
field = (*env)->GetFieldID(env, cls, "ptr", "J");
if (!field)
{
propagate_runtime(env, "Failed to look up the type field");
return NULL;
}
event = (DC_ClientEvent *)(*env)->GetLongField(env, this, field);
if (!event || !event->message)
{
throw_exc(env, CLASS_RuntimeDCException, "Empty message event?!?");
return NULL;
}
return (*env)->NewStringUTF(env, event->message);
}
/* Throws: RuntimeDCException */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_Event_finalize
(JNIEnv *env, jobject this)
{
DC_ClientEvent *event;
jfieldID field;
jclass cls;
cls = (*env)->GetObjectClass(env, this);
if (!cls)
return;
field = (*env)->GetFieldID(env, cls, "ptr", "J");
if (!field)
{
propagate_runtime(env, "Failed to look up the type field");
return;
}
event = (DC_ClientEvent *)(*env)->GetLongField(env, this, field);
DC_destroyClientEvent(event);
}
/**********************************************************************
* Class: hu.sztaki.lpds.dc.DCClient
*/
/* Throws: none */
JNIEXPORT jint JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_getMaxMessageSize
(JNIEnv *env G_GNUC_UNUSED, jclass cls G_GNUC_UNUSED)
{
return DC_getMaxMessageSize();
}
/* Throws: none */
JNIEXPORT jint JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_getMaxSubresults
(JNIEnv *env G_GNUC_UNUSED, jclass cls G_GNUC_UNUSED)
{
return DC_getMaxSubresults();
}
/* Throws: NullPointerException */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_log
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jint level, jstring msgstr)
{
const char *msg;
if (!msgstr)
{
throw_exc(env, CLASS_NullPointerException,
"Message cannot be null");
return;
}
msg = (*env)->GetStringUTFChars(env, msgstr, NULL);
if (!msg)
return;
DC_log(level, "%s", msg);
(*env)->ReleaseStringUTFChars(env, msgstr, msg);
}
/* Throws: NullPointerException, IllegalArgumentException */
JNIEXPORT jstring JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_getCfgStr
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring namestr)
{
const char *name;
jstring res;
char *value;
if (!namestr)
{
throw_exc(env, CLASS_NullPointerException,
"Configuration key name cannot be null");
return NULL;
}
name = (*env)->GetStringUTFChars(env, namestr, NULL);
if (!name)
return NULL;
value = DC_getCfgStr(name);
if (!value)
{
throw_exc(env, CLASS_IllegalArgumentException,
"Configuration key %s does not exist", name);
(*env)->ReleaseStringUTFChars(env, namestr, name);
return NULL;
}
res = (*env)->NewStringUTF(env, value);
free(value);
(*env)->ReleaseStringUTFChars(env, namestr, name);
return res;
}
/* Throws: NullPointerException */
JNIEXPORT jint JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_getCfgInt
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring namestr, jint defaultValue)
{
const char *name;
jint res;
if (!namestr)
{
throw_exc(env, CLASS_NullPointerException,
"Configuration key name cannot be null");
return defaultValue;
}
name = (*env)->GetStringUTFChars(env, namestr, NULL);
if (!name)
return defaultValue;
res = DC_getCfgInt(name, defaultValue);
(*env)->ReleaseStringUTFChars(env, namestr, name);
return res;
}
/* Throws: NullPointerException */
JNIEXPORT jboolean JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_getCfgBool
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring namestr, jboolean defaultValue)
{
const char *name;
jboolean res;
if (!namestr)
{
throw_exc(env, CLASS_NullPointerException,
"Configuration key name cannot be null");
return defaultValue;
}
name = (*env)->GetStringUTFChars(env, namestr, NULL);
if (!name)
return defaultValue;
res = DC_getCfgBool(name, defaultValue);
(*env)->ReleaseStringUTFChars(env, namestr, name);
return res;
}
/* Throws: DCException */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_init
(JNIEnv *env, jclass cls G_GNUC_UNUSED)
{
int ret;
ret = DC_initClient();
if (ret)
throw_dcexc(env, ret, "Failed to initialize the DC-API library");
}
/* Throws: DCException, NullPointerException */
JNIEXPORT jstring JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_resolveFileName
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jobject typeobj, jstring namestr)
{
DC_FileType type;
const char *name;
jfieldID field;
jstring res;
char *pname;
if (!typeobj)
{
throw_exc(env, CLASS_NullPointerException,
"The file type can not be null");
return NULL;
}
if (!namestr)
{
throw_exc(env, CLASS_NullPointerException,
"The file name can not be null");
return NULL;
}
cls = (*env)->GetObjectClass(env, typeobj);
if (!cls)
return NULL;
field = (*env)->GetFieldID(env, cls, "code", "I");
if (!field)
{
propagate_runtime(env, "Failed to look up the code field");
return NULL;
}
type = (*env)->GetIntField(env, typeobj, field);
name = (*env)->GetStringUTFChars(env, namestr, NULL);
pname = DC_resolveFileName(type, name);
(*env)->ReleaseStringUTFChars(env, namestr, name);
if (!pname)
{
throw_dcexc(env, DC_ERR_BADPARAM, "File name lookup failed");
return NULL;
}
res = (*env)->NewStringUTF(env, pname);
free(pname);
return res;
}
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_sendResult
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring namestr, jstring pathstr, jobject modeobj)
{
const char *name, *path;
DC_FileMode mode;
jfieldID field;
int ret;
if (!modeobj)
{
throw_exc(env, CLASS_NullPointerException,
"The file mode can not be null");
return;
}
if (!namestr)
{
throw_exc(env, CLASS_NullPointerException,
"The logical file name can not be null");
return;
}
if (!pathstr)
{
throw_exc(env, CLASS_NullPointerException,
"The physical file name can not be null");
return;
}
cls = (*env)->GetObjectClass(env, modeobj);
if (!cls)
return;
field = (*env)->GetFieldID(env, cls, "code", "I");
if (!field)
{
propagate_runtime(env, "Failed to look up the code field");
return;
}
mode = (*env)->GetIntField(env, modeobj, field);
name = (*env)->GetStringUTFChars(env, namestr, NULL);
path = (*env)->GetStringUTFChars(env, pathstr, NULL);
ret = DC_sendResult(name, path, mode);
(*env)->ReleaseStringUTFChars(env, namestr, name);
(*env)->ReleaseStringUTFChars(env, pathstr, path);
if (ret)
throw_dcexc(env, ret, "Sub-result sending failed");
}
/* Throws: NullPointerException */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_sendMessage
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring msgstr)
{
const char *msg;
if (!msgstr)
{
throw_exc(env, CLASS_NullPointerException,
"The message can not be null");
return;
}
msg = (*env)->GetStringUTFChars(env, msgstr, NULL);
DC_sendMessage(msg);
(*env)->ReleaseStringUTFChars(env, msgstr, msg);
}
/* Throws: none */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_finish
(JNIEnv *env G_GNUC_UNUSED, jclass cls G_GNUC_UNUSED, jint exitCode)
{
DC_finishClient(exitCode);
}
/* Throws: NullPointerException */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_checkpointMade
(JNIEnv *env, jclass cls G_GNUC_UNUSED, jstring pathstr)
{
const char *path;
if (!pathstr)
{
throw_exc(env, CLASS_NullPointerException,
"The file name can not be null");
return;
}
path = (*env)->GetStringUTFChars(env, pathstr, NULL);
DC_checkpointMade(path);
(*env)->ReleaseStringUTFChars(env, pathstr, path);
}
/* Throws: none */
JNIEXPORT void JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_fractionDone
(JNIEnv *env G_GNUC_UNUSED, jclass cls G_GNUC_UNUSED, jdouble fraction G_GNUC_UNUSED)
{
DC_fractionDone(fraction);
}
/* Throws: none */
JNIEXPORT jobject JNICALL Java_hu_sztaki_lpds_dc_client_DCClient_checkEvent
(JNIEnv *env, jclass cls G_GNUC_UNUSED)
{
DC_ClientEvent *event;
jobject eventobj;
jmethodID meth;
int ret;
event = DC_checkClientEvent();
if (!event)
return NULL;
ret = GET_CTOR(env, ClientEvent, &cls, &meth);
if (ret)
return NULL;
eventobj = (*env)->NewObject(env, cls, meth, event->type, (jlong)event);
return eventobj;
}
/**********************************************************************
* Class: hu.sztaki.lpds.dc.client.Version
*/
JNIEXPORT jstring JNICALL Java_hu_sztaki_lpds_dc_client_Version_getNativeVersion
(JNIEnv *env, jclass cls G_GNUC_UNUSED)
{
return (*env)->NewStringUTF(env, PACKAGE_VERSION);
}
/**********************************************************************
* JNI module initialization and finalization
*/
JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void *res G_GNUC_UNUSED)
{
union getenvarg jnienv;
const char *ver;
jmethodID meth;
jstring verstr;
jclass cls;
int ret;
myvm = jvm;
if ((*myvm)->GetEnv(myvm, &jnienv.ptr, JNI_VERSION_1_2))
return 0;
/* Check that the JNI and Java versions match */
cls = find_class(jnienv.env, CLASS_ClientVersion);
if (!cls)
{
fprintf(stderr, "Class hu.sztaki.lpds.dc.Version was "
"not found\n");
return 0;
}
meth = (*jnienv.env)->GetStaticMethodID(jnienv.env, cls, "getVersion",
SIG_ClientVersion_getVersion);
if (!meth)
{
fprintf(stderr, "Method hu.sztaki.lpds.dc.Version."
"getVersion() was not found\n");
return 0;
}
verstr = (*jnienv.env)->CallStaticObjectMethod(jnienv.env, cls, meth);
if ((*jnienv.env)->ExceptionCheck(jnienv.env))
{
fprintf(stderr, "Exception occurred while checking the "
"version\n");
return 0;
}
ver = (*jnienv.env)->GetStringUTFChars(jnienv.env, verstr, NULL);
if (!ver)
{
fprintf(stderr, "Failed to retrieve the version string\n");
return 0;
}
if (strcmp(ver, PACKAGE_VERSION))
{
fprintf(stderr, "DC-API version mismatch: Java side is %s, "
"JNI side is %s\n", ver, PACKAGE_VERSION);
(*jnienv.env)->ReleaseStringUTFChars(jnienv.env, verstr, ver);
return 0;
}
(*jnienv.env)->ReleaseStringUTFChars(jnienv.env, verstr, ver);
(*jnienv.env)->DeleteLocalRef(jnienv.env, verstr);
(*jnienv.env)->DeleteLocalRef(jnienv.env, cls);
/* Look for & process dc.jni.debug */
ret = parse_debug_options(jnienv.env);
if (ret)
return 0;
return JNI_VERSION_1_2;
}
JNIEXPORT void JNI_OnUnload(JavaVM *jvm G_GNUC_UNUSED,
void *res G_GNUC_UNUSED)
{
}