JIN c++ with springboot (Tomcat ENV->FindClass return null) - java-native-interface

I'm trying to call a java function by C++. It is working perfectly fine in Eclipse IDE, but when i build war and running in tomcat. I'm able to call C++ function from Springboot application. But unable to call java function from C++. Since It is unable to find the class which i mentioned with package.
Below is my sample code. Is their is anyway to fix this?
my C++ code
void myClientEvents::SendEvents(const char* ack) {
//Get current thread JNIEnv
JNIEnv * ENV;
WriteLogFile("Get current thread JNIEnv");
try {
WriteLogFile(ack);
int stat = savedVM->GetEnv((void **)&ENV, JNI_VERSION_1_8);
WriteLogFile("stat");
if (stat == JNI_EDETACHED) //We are on a different thread, attach
{
WriteLogFile("We are on a different thread, attach");
savedVM->AttachCurrentThread((void **)&ENV, NULL);
}
if (ENV == NULL)
{
WriteLogFile("Cant attach to java, bail");
//Cant attach to java, bail
}
//Get the Listener class reference
if (saved_listener_instance != NULL) {
WriteLogFile("Get the Listener class reference");
jclass listenerClassRef = ENV->FindClass("org/trinity/serviceImpl/CadiAstroServiceImpl");
if (listenerClassRef==NULL)
{
WriteLogFile("Class Not found"); //This line is printing for tomcat
}
WriteLogFile("Use Listener class reference to load the eventOccurred method");
//Not moving forward from above log in tomcat
jmethodID ctor = ENV->GetMethodID(listenerClassRef, "<init>", "()V");
jobject object = ENV->NewObject(listenerClassRef, ctor);
//Use Listener class reference to load the eventOccurred method
jmethodID listenerEventOccured = ENV->GetMethodID(listenerClassRef, "eventOccurred", "(Ljava/lang/String;)V");
WriteLogFile("jmethodID created");
jstring jstr = ENV->NewStringUTF(ack);
WriteLogFile("invoke listener eventOccurred");
//invoke listener eventOccurred
ENV->CallVoidMethod(object, listenerEventOccured, jstr);
ENV->DeleteLocalRef(jstr);
ENV->DeleteLocalRef(object);
ENV->DeleteLocalRef(listenerClassRef);
}
else {
WriteLogFile("Error getting class");
}
}
catch (const char* msg) {
WriteLogFile(msg);
}
}
my java method in mentioned class
public void eventOccurred(String info) {
System.out.println(info);
}

Related

sd-bus signal not calling cb function

I have one problem. In c++ app, I am using sd-bus and signal does not call my callback function.
I hooked to org.freedesktop.login1, interface is org.freedesktop.DBus.Properties, member is PropertiesChanged and path is /org/freedesktop/login1/seat/seat0
In my connect method I have this:
sd_bus_add_match(m_bus, NULL, "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/login1/seat/seat0',type='signal'", on_properties_changed, NULL)
On properties changed method is this:
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
printf("got some signal");
}
So, when I ran this program, I also ran following command in cmd:ΒΈ
gdbus monitor --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1/seat/seat0
However, when I switch from userA to userB, I got following line in cmd window:
/org/freedesktop/login1/seat/seat0: org.freedesktop.DBus.Properties.PropertiesChanged ('org.freedesktop.login1.Seat', {'ActiveSession': <('c7', objectpath '/org/freedesktop/login1/session/c7')>}, #as [])
Also when I tried this
busctl --system --match "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/login1/seat/seat0',type='signal' monitor
then I also get proper response
Type=signal Endian=l Flags=1 Version=1 Priority=0 Cookie=2281
Sender=:1.0 Path=/org/freedesktop/login1/seat/seat0 Interface=org.freedesktop.DBus.Properties Member=PropertiesChanged
UniqueName=:1.0
MESSAGE "sa{sv}as" {
STRING "org.freedesktop.login1.Seat";
ARRAY "{sv}" {
DICT_ENTRY "sv" {
STRING "ActiveSession";
VARIANT "(so)" {
STRUCT "so" {
STRING "c2";
OBJECT_PATH "/org/freedesktop/login1/session/c2";
};
};
};
};
ARRAY "s" {
};
};
But in c++ that callback function is not called. Any idea why is it not called?
I am using Ubuntu 16.04 and my systemd version is 229.
I found a solution to this problem. Problem was that I wasn't hooked to any event loop.
So I created new function run() and in this function I say this:
while(m_running) {
sd_bus_message *m = NULL;
r = sd_bus_process(m_bus, &m);
if (r < 0) {
//error handling
}
r = sd_bus_wait(m_bus, (uint64_t)-1);
if (r < 0) {
//error handling
}
}
and now I call this function after I connect to signal, and callback function of sd_bus_add_match is normally called

gRPC and etcd client

This question involves etcd specific stuff, but I think the question more related to work with gRPC in general.
I'm trying to create etcd Watch for some keys, since the documentation is sparse I had a look at Nokia implementation
It was easy to adapt code to my needs and I came up with first version which worked just fine, creating WatchCreateRequest, and firing callback on key update. So far so good. Then I've tried to add more than one key to watch. Fiasco! ClientAsyncReaderWriter is failing to Read/Write in such a case. Now to the question.
If I have following members in my class
Watch::Stub watchStub;
CompletionQueue completionQueue;
ClientContext context;
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
WatchResponse reply;
and I want to support multiple Watches added to my class, I guess I have to hold several variables per watch and not as class members.
First of all, I guess, WatchResponse reply should be one per Watch. I'm less sure about the stream, should I hold one per Watch? I'm almost sure that context could be reused for all Watches and 100% sure the stub and completionQueue can be reused for all Watches.
So the question is my guess-work right? Whats about thread safety? Didnt find any documentation describing what objects are safe to use from multiple thread and where I have to synchronize access.
Any link to documentation (not this one) will be appreciated!
Test code before I split members into single Watch property
(no proper shutdown, I know)
using namespace grpc;
class Watcher
{
public:
using Callback = std::function<void(const std::string&, const std::string&)>;
Watcher(std::shared_ptr<Channel> channel) : watchStub(channel)
{
stream = watchStub.AsyncWatch(&context, &completionQueue, (void*) "create");
eventPoller = std::thread([this]() { WaitForEvent(); });
}
void AddWatch(const std::string& key, Callback callback)
{
AddWatch(key, callback, false);
}
void AddWatches(const std::string& key, Callback callback)
{
AddWatch(key, callback, true);
}
private:
void AddWatch(const std::string& key, Callback callback, bool isRecursive)
{
auto insertionResult = callbacks.emplace(key, callback);
if (!insertionResult.second) {
throw std::runtime_error("Event handle already exist.");
}
WatchRequest watch_req;
WatchCreateRequest watch_create_req;
watch_create_req.set_key(key);
if (isRecursive) {
watch_create_req.set_range_end(key + "\xFF");
}
watch_req.mutable_create_request()->CopyFrom(watch_create_req);
stream->Write(watch_req, (void*) insertionResult.first->first.c_str());
stream->Read(&reply, (void*) insertionResult.first->first.c_str());
}
void WaitForEvent()
{
void* got_tag;
bool ok = false;
while (completionQueue.Next(&got_tag, &ok)) {
if (ok == false) {
break;
}
if (got_tag == (void*) "writes done") {
// Signal shutdown
}
else if (got_tag == (void*) "create") {
}
else if (got_tag == (void*) "write") {
}
else {
auto tag = std::string(reinterpret_cast<char*>(got_tag));
auto findIt = callbacks.find(tag);
if (findIt == callbacks.end()) {
throw std::runtime_error("Key \"" + tag + "\"not found");
}
if (reply.events_size()) {
ParseResponse(findIt->second);
}
stream->Read(&reply, got_tag);
}
}
}
void ParseResponse(Callback& callback)
{
for (int i = 0; i < reply.events_size(); ++i) {
auto event = reply.events(i);
auto key = event.kv().key();
callback(event.kv().key(), event.kv().value());
}
}
Watch::Stub watchStub;
CompletionQueue completionQueue;
ClientContext context;
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
WatchResponse reply;
std::unordered_map<std::string, Callback> callbacks;
std::thread eventPoller;
};
I'm sorry that I'm not very sure about the proper Watch design here. It's not very clear to me whether you want to create a gRPC call for each Watch.
Anyway, each gRPC call will have its own ClientContext, ClientAsyncReaderWriter. But stub and CompletionQueue is not per-call thing.
As far as I know, there is no central place to find the thread-safe classes. You may want to read the API document to have a correct expectation.
When I was writing the async server load reporting service, the only place I add synchronization myself is around CompletionQueue, so that I don't en-queue new tags to the cq if it's shut down.

Native IIS7.5 Module not running

I've created a simple CHttpModule that adds a custom header to all requests:
#define _WINSOCKAPI_
#include <windows.h>
#include <sal.h>
#include <httpserv.h>
class AppendHeaderModule : public CHttpModule {
public:
REQUEST_NOTIFICATION_STATUS
OnBeginRequest(
IN IHttpContext * pHttpContext,
IN IHttpEventProvider * pProvider
)
{
UNREFERENCED_PARAMETER(pProvider);
PCSTR testHeaderName = "Foo";
PCSTR testHeader = "bar";
pHttpContext->GetResponse()->SetHeader(testHeaderName, testHeader, (USHORT)strlen(testHeader), true);
return RQ_NOTIFICATION_CONTINUE;
}
VOID Terminate() {
delete this;
}
AppendHeaderModule() { }
~AppendHeaderModule() { }
};
class AppendHeaderModuleFactory : public IHttpModuleFactory {
public:
HRESULT
GetHttpModule(
OUT CHttpModule ** ppModule,
IN IModuleAllocator * pAllocator
)
{
UNREFERENCED_PARAMETER(pAllocator);
AppendHeaderModule* pModule = new AppendHeaderModule;
if (!pModule) {
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
}
else {
*ppModule = pModule;
pModule = NULL;
return S_OK;
}
}
void Terminate() {
delete this;
}
};
HRESULT __stdcall
RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pGlobalInfo
)
{
UNREFERENCED_PARAMETER(dwServerVersion);
UNREFERENCED_PARAMETER(pGlobalInfo);
AppendHeaderModuleFactory* pModule = new AppendHeaderModuleFactory;
if (pModule == NULL)
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
return pModuleInfo->SetRequestNotifications(pModule, RQ_BEGIN_REQUEST, 0);
}
I've copied it to C:\Windows\System32\inetsrv, registered the module, and added it to the list. However, I'm not seeing the additional header in any of my requests. I created a similar managed module, installed it to the GAC, registered it, and it works fine. But this native module seems to do nothing. Is there another step required to get native modules to handle requests?
Also, I'm not sure if it matters, but the requests are being made to an ASP.NET site. Do native handlers not run for ASP.NET?
If the module is a 32-bit module you need to enable 32-bit applications in the application pool for your website. Go to the Application Pools, select the pool for your website, Advanced Settings and set "Enable 32-Bit Applications to TRUE.

WaitOne() timeout parameter lost?

why System.Threading.WaitHandle.WaitOne() hasn't overload for the timeout parameters as available in standard .NET implementation: http://msdn.microsoft.com/en-us/library/cc189907(v=vs.110).aspx
It's very useful in working threads when, during thread sleep, thread is requested to stop from Main UI thread.. Other ways to implement it?
Example:
public void StartBatteryAnimation()
{
whStopThread = new ManualResetEvent(false);
batteryAnimationThread = new Thread(new ThreadStart(BatteryAnimation_Callback));
batteryAnimationThread.Start();
}
public void StopBatteryAnimation()
{
whStopThread.Set();
batteryAnimationThread.Join();
batteryAnimationThread = null;
whStopThread.Dispose();
whStopThread = null;
}
public void BatteryAnimation_Callback()
{
bool exitResult = false;
while (true)
{
// Do some stuff
exitResult = whStopThread.WaitOne(WAIT_INTERVALL);
if (exitResult) break;
}
}
Thanks Frank for your (1000th!!) reply.
So my custom implementation for WaitHandle.WaitOne(int Timeout) has been:
private Thread batteryAnimationThread = null;
private Semaphore batteryAnimationSemaphore = null;
public void StartBatteryAnimation()
{
batteryAnimationSemaphore = new Semaphore(1);
batteryAnimationSemaphore.Acquire();
batteryAnimationThread = new Thread(new ThreadStart(BatteryAnimation_Callback));
batteryAnimationThread.Start();
}
public void StopBatteryAnimation()
{
batteryAnimationSemaphore.Release();
batteryAnimationThread.Join();
batteryAnimationThread = null;
batteryAnimationSemaphore = null;
}
public void BatteryAnimation_Callback()
{
bool stopThread = false;
try
{
while (true)
{
// Do some stuff..
stopThread = batteryAnimationSemaphore.TryAcquire(1, BATTERY_ANIMATION_INTERVALL, Java.Util.Concurrent.TimeUnit.MILLISECONDS);
if (stopThread) break;
}
catch (Exception ex)
{
}
batteryAnimationSemaphore.Release();
}
Is this the right way for?
Thanks
This one hasn't been implemented yet. You may use semaphore.tryAcquire instead.
Background: Due to its design, dot42 supports the entire Android API (C# classes are proxies and generated from the android.jar). But is supports only part of the .NET API because the .NET classes are handcrafted on top of the Android/Java API.
Related question: Java Equivalent of .NET's ManualResetEvent and WaitHandle
UPDATE
We released the API under Apache License 2.0 so anyone may contribute now. I also logged an issue.

Trouble calling on a Java method from a native thread using JNI (C++)

I have a JNI problem which I hope someone can help me out with.
I'm trying to call on a constructor of a Java class called LUSOutputJNI from a native thread.
It keeps failing on FindClass(...) of this specific class.
Here is the code:
LOGE("1");
JNIEnv *env = NULL;
LOGE("2");
int res = -1;
res = g_vm->AttachCurrentThread(&env, NULL);
if(env == NULL)
{
LOGE("env is NULL, AttachCurrentThread failed");;
}
if(res >= 0)
LOGE("AttachCurrentThread was successful");
jclass clazz = NULL;
jmethodID cid;
jclass clazzESEngine;
jmethodID callbackid;
jobject jCoreOut;
static jfieldID fid_ActionState = NULL;
static jfieldID fid_nSpeed = NULL;
static jfieldID fid_nType = NULL;
static jfieldID fid_nInProcess = NULL;
static jfieldID fid_nX = NULL;
static jfieldID fid_nY = NULL;
LOGE("3");
static const char* const ECOClassName = "lus/android/sdk/LUSOutputJNI";
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");
LOGE("4");
cid = env->GetMethodID(clazz,"<init>", "()V");
LOGE("5");
jCoreOut = env->NewObject(clazz, cid);
LOGE("6");
Here is the logcat output from when it fails:
E/lusCore_JNI( 3040): 1
E/lusCore_JNI( 3040): 2
E/lusCore_JNI( 3040): AttachCurrentThread was successful
E/lusCore_JNI( 3040): 3
E/lusCore_JNI( 3040): Can't find class LUSOutputJNI
E/lusCore_JNI( 3040): 4
W/dalvikvm( 3040): JNI WARNING: JNI method called with exception raised
Observations:
I get a result from AttachCurrentThread which is 0, which means that this attachment was successful + the env pointer is no longer NULL.
I'm sure about the package name declaration of LUSOutputJNI (triple checked it...)
When I try to run FindClass(..) with a more popular class name such as android/widget/TextView , I get a positive match. It is there. Meaning the thread attachment and the env variables are ok. (Can I assume that?)
When I try to run the following code from a JNI method which has a JNI thread running it, it finds the LUSOutputJNI class without a problem.
What am I doing wrong?
Help will be much appreciated :)
Thanks for your time,
Ita
Found the answer \ work around in here. (Look for FAQ: "FindClass didn't find my class" in
JNI tips)
I basicaly saved a global ref to the needed jclass objects.
Did however had to overcome some evil JNI changes between C/JNI and C++/JNI in order for the code to compile.
This is how I got the NewGlobalRef to compile and work.
jclass localRefCls = env->FindClass(strLUSClassName);
if (localRefCls == NULL) {
LOGE("Can't find class %s",strLUSCoreClassName);
return result;
}
//cache the EyeSightCore ref as global
/* Create a global reference */
clazzLUSCore = (_jclass*)env->NewGlobalRef(localRefCls);
/* The local reference is no longer useful */
env->DeleteLocalRef(localRefCls);
/* Is the global reference created successfully? */
if (clazzLUSCore == NULL) {
LOGE("Error - clazzLUSCore is still null when it is suppose to be global");
return result; /* out of memory exception thrown */
}
I hope this helps anyone.
To get a bit more information about whats going wrong ( it will log to stderr, not LOGE, and I'm not sure how to change that) you can add some exception printing - you can change this:
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");
To this:
//static const char* const ECOClassName = "android/widget/TextView";
clazz = env->FindClass(ECOClassName);
if (clazz == NULL) {
LOGE("Can't find class LUSOutputJNI");
jthrowable exc = env->ExceptionOccurred();
if(exc)
{
env->ExceptionDescribe();
env->ExceptionClear();
}
}
else
LOGE("lus/android/sdk/LUSOutputJNI was found, YEY!!");