#include "de_mrbesen_cppplugins_CppPlugin.h" #include "de_mrbesen_cppplugins_CppPlugin_CppListener.h" #include #include //dynamic linking #include JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_init_1(JNIEnv* env, jobject thisobj) { std::cout << "init libplugin loading java references, 1 = good, 0 = bad" << std::endl; CPPPLUGINCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin"); EVENTCLASS = env->FindClass("de/mrbesen/cppplugins/CppEvent"); MAPCLASS = env->FindClass("java/util/Map"); LISTENERCLASS = env->FindClass("de/mrbesen/cppplugins/CppPlugin$CppListener"); std::cout << "find classes: " << (!!CPPPLUGINCLASS) << (!!EVENTCLASS) << (!!MAPCLASS) << (!!LISTENERCLASS) << std::endl; EVENTDATAF = env->GetFieldID(EVENTCLASS, "data", "Ljava/util/Map;"); EVENTNAMEF = env->GetFieldID(EVENTCLASS, "name", "Ljava/lang/String;"); std::cout << "findfields: " << (!!EVENTDATAF) << (!!EVENTNAMEF) << std::endl; MAPGET = env->GetMethodID(MAPCLASS, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); MAPPUT = env->GetMethodID(MAPCLASS, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); LISTENERCONTR = env->GetMethodID(LISTENERCLASS, "", "(Ljava/lang/String;J)V"); std::cout << "find methods: " << (!!MAPGET) << (!!MAPPUT) << (!!LISTENERCONTR) << std::endl; return ((!CPPPLUGINCLASS) + (!EVENTCLASS) + (!MAPCLASS) + (!EVENTDATAF) + (!EVENTNAMEF) + (!MAPGET) + (!MAPPUT) + (!LISTENERCONTR)) == 0; //one nullptr -> inverted to 1 -> ends up at end -> false } /** * Class: de_mrbesen_cppplugins_CppPlugin * Method: loadPlugin * Signature: (Ljava/lang/String;)Z */ JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_loadPlugin(JNIEnv* env, jobject thisobj, jstring path) { const char* cpath = env->GetStringUTFChars(path, 0); //open plugin std::cout << "open plugin " << cpath << std::endl; void* handle = dlopen(cpath, RTLD_LAZY); if (!handle) { std::cout << "could not create handle of: " << cpath << " error: " << dlerror() << std::endl; return false; } //throw std::string("Error: plugin could not be opend. ") + dlerror(); //load function pointer initfptr initf = (initfptr) dlsym(handle, "init"); if(!initf) { std::cout << "Could not find function init: " << dlerror() << std::endl; dlclose(handle); return false; } plugin = initf(); plugin->handle = handle; //store data //setData(data, env, thisobj); std::cout << "plugin: " << (bool)plugin << std::endl; return (bool) plugin; // converted to boolean here } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onLoad * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onLoad(JNIEnv* env, jobject thisobj) { //TODO std::cout << "lib::onLoad()" << std::endl; plugin->onLoad(); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onEnable_ * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onEnable_1(JNIEnv* env, jobject thisobj) { //TODO std::cout << "lib::onEnable()" << std::endl; plugin->onEnable(); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onDisable_ * Signature: ()V */ JNIEXPORT void JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onDisable_1(JNIEnv* env, jobject thisobj) { //TODO std::cout << "lib::onDisable()" << std::endl; plugin->onDisable(); dlclose(plugin->handle); } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: fireEvent * Signature: (Lde/mrbesen/cppplugins/CppEvent;I)Lde/mrbesen/cppplugins/CppEvent; */ JNIEXPORT jobject JNICALL Java_de_mrbesen_cppplugins_CppPlugin_fireEvent(JNIEnv* env, jobject thisobj, jobject jevent, jlong functionid) { std::cout << "lib::fireEvent()" << std::endl; if(functionid == 0) { std::cout << "invalid function id" << std::endl; return jevent; } //cast function eventfptr f = reinterpret_cast(functionid); //cast event Event event(env, jevent); //call it f(plugin, &event); //put changed fields back in the jevent event.reapply(env, jevent); return jevent; } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: onCmd * Signature: (Lorg/bukkit/command/CommandSender;Lorg/bukkit/command/Command;Ljava/lang/String;[Ljava/lang/String;)Z */ JNIEXPORT jboolean JNICALL Java_de_mrbesen_cppplugins_CppPlugin_onCmd(JNIEnv* env, jobject thisobj, jobject sender, jobject cmd, jstring label, jobjectArray args) { //TODO return false; } /* * Class: de_mrbesen_cppplugins_CppPlugin * Method: getListener * Signature: ()[Lde/mrbesen/cppplugins/CppPlugin/CppListener; */ JNIEXPORT jobjectArray JNICALL Java_de_mrbesen_cppplugins_CppPlugin_getListener(JNIEnv* env, jobject thisobj) { //call getEvents std::map events; getEventsfptr getEventsf = (getEventsfptr) dlsym(plugin->handle, "getEvents"); if(getEventsf) { //only non null events = getEventsf(); } //create array jclass clas = env->FindClass("de/mrbesen/cppplugins/CppPlugin/CppListener"); jobjectArray arr = env->NewObjectArray(events.size(), clas, 0); //populate array int i = 0; for(auto it : events) { //create object jstring eventname = env->NewStringUTF(it.first.c_str()); jobject listener = env->NewObject(LISTENERCLASS, LISTENERCONTR, eventname, it.second); env->DeleteLocalRef(eventname); //set array env->SetObjectArrayElement(arr, i++, listener); } return arr; } ///////// EVENTS jobject Event::getMap(JNIEnv* env) { return env->GetObjectField(input, EVENTDATAF); } const std::string& Event::getName() { return name; } void* Event::getData(JNIEnv* env, const std::string& name) { std::cout << "Try to access " << name << std::endl; //search in map auto it = data.find(name); if(it == data.end()) { //search in original object //construct string jstring term = env->NewStringUTF(name.c_str()); //call data.get() jobject map = getMap(env); jobject content = env->CallObjectMethod(map, MAPGET, term); //data.insert for next time data.insert({name, content}); //delete string env->DeleteLocalRef(term); } else { return it->second; } return nullptr; } void Event::setData(const std::string& name, void* d) { //just put it in the map data.insert({name, d}); } void Event::reapply(JNIEnv* env, jobject jevent) { jobject map = getMap(env); for(auto it : data) { std::cout << "write back to java: " << it.first << std::endl; jstring key = env->NewStringUTF(it.first.c_str()); env->CallObjectMethod(map, MAPPUT, key, it.second); env->DeleteLocalRef(key); } } Event::Event(JNIEnv* env, jobject jevent) { //get name jstring name = (jstring) env->GetObjectField(jevent, EVENTNAMEF); this->name = std::string(env->GetStringUTFChars(name, 0)); input = jevent; }