| /* | |
| * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| #ifndef __CallHelper_hpp__ | |
| #define __CallHelper_hpp__ | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <jni.h> | |
| #undef NDEBUG | |
| #include <assert.h> | |
| #include <string> | |
| #include <algorithm> | |
| /* | |
| * basis of classes to provide a bunch of checking in native calls to java | |
| */ | |
| class CallHelper { | |
| public: | |
| CallHelper(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) : | |
| classname(cname), method(mname), signature(sig), m(nullptr), env(e) { | |
| c = env->FindClass(classname.c_str()); | |
| assert (c != nullptr); | |
| } | |
| protected: | |
| // emit a message with the call made appended to the message | |
| void emitErrorMessage(const std::string& msg) { | |
| std::string nm = classname; | |
| std::replace(nm.begin(), nm.end(), '/', '.'); | |
| ::fprintf(stderr, "ERROR: %s::%s, %s\n", nm.c_str(), method.c_str(), msg.c_str()); | |
| } | |
| // check the given object which is expected to be null | |
| void checkReturnNull(jobject obj) { | |
| if (obj != nullptr) { | |
| emitErrorMessage("Null return expected"); | |
| ::exit(-1); | |
| } | |
| } | |
| // check the given object which is expected to NOT be null | |
| void checkReturnNotNull(jobject obj) { | |
| if (obj == nullptr) { | |
| emitErrorMessage("Non-Null return expected"); | |
| ::exit(-1); | |
| } | |
| } | |
| // check if any unexpected exceptions were thrown | |
| void checkException() { | |
| if (env->ExceptionOccurred() != nullptr) { | |
| emitErrorMessage("Exception was thrown"); | |
| env->ExceptionDescribe(); | |
| ::exit(-1); | |
| } | |
| } | |
| // check if an expected exception was thrown | |
| void checkExpectedExceptionThrown(const std::string& exception) { | |
| jclass expected = env->FindClass(exception.c_str()); | |
| assert(expected != nullptr); | |
| jthrowable t = env->ExceptionOccurred(); | |
| if (env->IsInstanceOf(t, expected) == JNI_FALSE) { | |
| emitErrorMessage("Didn't get the expected " + exception); | |
| ::exit(-1); | |
| } | |
| env->ExceptionClear(); | |
| } | |
| protected: | |
| std::string classname; | |
| std::string method; | |
| std::string signature; | |
| jclass c; | |
| jmethodID m; | |
| JNIEnv* env; | |
| }; | |
| /* | |
| * support for making checked calls on instances of an object | |
| */ | |
| class InstanceCall : public CallHelper { | |
| public: | |
| InstanceCall(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) | |
| : CallHelper(e, cname, mname, sig) { | |
| m = env->GetMethodID(c, method.c_str(), signature.c_str()); | |
| assert(m != nullptr); | |
| } | |
| // call on the given object, checking for exceptions and that the return is not null | |
| jobject callReturnNotNull(jobject obj) { | |
| jobject robj = call(obj); | |
| checkReturnNotNull(robj); | |
| return robj; | |
| } | |
| // call on the given object with an argument, | |
| // checking for exceptions and that the return is not null | |
| jobject callReturnNotNull(jobject obj, jobject arg) { | |
| jobject robj = call(obj, arg); | |
| checkReturnNotNull(robj); | |
| return robj; | |
| } | |
| // call on the given object, checking for exceptions and that the return is null | |
| jobject callReturnIsNull(jobject obj) { | |
| jobject robj = call(obj); | |
| checkReturnNull(robj); | |
| return robj; | |
| } | |
| // call on the given object with an argument, | |
| // checking for exceptions and that the return is null | |
| jobject callReturnIsNull(jobject obj, jobject arg) { | |
| jobject robj = call(obj, arg); | |
| checkReturnNull(robj); | |
| return robj; | |
| } | |
| // call a void method checking if exceptions were thrown | |
| void callVoidMethod(jobject obj) { | |
| env->CallVoidMethod(obj, m); | |
| checkException(); | |
| } | |
| jobject call(jobject obj) { | |
| jobject robj = env->CallObjectMethod(obj, m); | |
| checkException(); | |
| return robj; | |
| } | |
| jobject call(jobject obj, jobject arg) { | |
| jobject robj = env->CallObjectMethod(obj, m, arg); | |
| checkException(); | |
| return robj; | |
| } | |
| }; | |
| /* | |
| * support for making checked static calls | |
| */ | |
| class StaticCall : public CallHelper { | |
| public: | |
| StaticCall(JNIEnv* e, const std::string& cname, const std::string& mname, const std::string& sig) | |
| : CallHelper(e, cname, mname, sig) { | |
| m = env->GetStaticMethodID(c, method.c_str(), signature.c_str()); | |
| assert(m != nullptr); | |
| } | |
| // call a method returning an object checking for exceptions and | |
| // the return value is not null. | |
| jobject callReturnNotNull(jobject arg) { | |
| jobject robj = env->CallStaticObjectMethod(c, m, arg); | |
| checkException(); | |
| checkReturnNotNull(robj); | |
| return robj; | |
| } | |
| // call a void method checking if any exceptions thrown | |
| void callVoidMethod() { | |
| env->CallStaticVoidMethod(c, m); | |
| checkException(); | |
| } | |
| // call method returning boolean that is expected to throw the | |
| // given exception | |
| void callBooleanMethodWithException(const std::string& exception) { | |
| env->CallStaticBooleanMethod(c, m); | |
| checkExpectedExceptionThrown(exception); | |
| } | |
| // call method returning an object that is expected to throw the | |
| // given exception | |
| void callObjectMethodWithException(const std::string& exception) { | |
| env->CallStaticObjectMethod(c, m); | |
| checkExpectedExceptionThrown(exception); | |
| } | |
| }; | |
| void emitErrorMessageAndExit(const std::string& msg) { | |
| ::fprintf(stderr, "ERROR: %s\n", msg.c_str()); | |
| ::exit(-1); | |
| } | |
| #endif // __CallHelper_hpp__ | |