Reputation: 13257
I am trying to launch jvm
for my server java program. Server java program internally launches another java
process and the class/method which I am calling has system.exist(0)
My program works fine , it launches the required java process but program control does not come back to c++. It just exist i.e. parent process dies.
Here is my complete code.
#include <stdexcept>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <include/jni.h>
#include <string>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <signal.h>
class JVMLauncherException : public std::runtime_error {
public:
JVMLauncherException(const std::string& message) : std::runtime_error(message)
{
};
};
class Server_JVMLauncher {
public:
Server_JVMLauncher();
void addJars(std::string inJar);
void LaunchJVM();
void StartServer_Server();
void AddServerArguments(std::string);
void StopServer_Server();
private:
typedef jint (JNICALL *CreateJavaVM)(JavaVM **pvm, void **penv, void *args);
HINSTANCE m_hDllInstance;
std::string m_JavaHome;
std::string m_ProductLibDir;
std::string m_JvmDllLocation;
CreateJavaVM m_JVMInstance;
jclass m_CacheServerLauncherClass;
jmethodID m_MainMethodID;
JNIEnv *m_JVMEnv;
JavaVM *m_RunningJVMInstance;
std::vector<std::string> m_listOfJars;
std::vector<std::string> m_ServerArguments;
void CheckForJNIException();
protected:
};
Server_JVMLauncher::Server_JVMLauncher() {
// Check for JAVA_HOME
char *pValue;
size_t len;
errno_t err = _dupenv_s( &pValue, &len, "JAVA_HOME" );
if ( err ) {
throw JVMLauncherException("JAVA_HOME not defined");
}
m_JavaHome = pValue;
m_JvmDllLocation = m_JavaHome + "\\jre\\bin\\client\\jvm.dll";
err = _dupenv_s( &pValue, &len, "Server_" );
if ( err ) {
throw JVMLauncherException("Server_ not defined");
}
m_ProductLibDir = pValue;
m_listOfJars.push_back("dep1.jar");
m_listOfJars.push_back("dep2.jar");
m_listOfJars.push_back("dep3.jar");
m_listOfJars.push_back("dep4.jar");
m_listOfJars.push_back("dep5.jar");
}
void Server_JVMLauncher::AddServerArguments(std::string inParam) {
m_ServerArguments.push_back(inParam);
}
void Server_JVMLauncher::LaunchJVM() {
// Construct the product specific class path.
std::string strJavaClassPath = "-Djava.class.path=";
for ( std::size_t idx = 0; idx < m_listOfJars.size() - 1 ; idx++) {
strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[idx] + ";";
}
strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[m_listOfJars.size() - 1] ;
// consruct java.library.path
std::string strJavaLibraryPath = "-Djava.library.path=";
strJavaLibraryPath += m_JavaHome + "\\lib" + "," + m_JavaHome + "\\jre\\lib";
// try loading jvm dll
m_hDllInstance = LoadLibraryA(m_JvmDllLocation.c_str());
if( m_hDllInstance == 0) {
throw JVMLauncherException("Cannot load jvm.dll");
}
m_JVMInstance = (CreateJavaVM)GetProcAddress(m_hDllInstance, "JNI_CreateJavaVM");
if ( m_JVMInstance == NULL ) {
throw JVMLauncherException("Cannot load jvm.dll");
}
JavaVMOption options[2];
options[0].optionString = const_cast<char*>(strJavaClassPath.c_str());
options[1].optionString = const_cast<char*>(strJavaLibraryPath.c_str());
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6; //JNI Version 1.4 and above
vm_args.options = options;
vm_args.nOptions = 2;
vm_args.ignoreUnrecognized = JNI_TRUE;
//Create the JVM
jint res = m_JVMInstance(&m_RunningJVMInstance, (void **)&m_JVMEnv, &vm_args);
if (res < 0) {
throw JVMLauncherException("Could not launch the JVM");
}
//m_RunningJVMInstance->AttachCurrentThread((void **)&m_JVMEnv, &vm_args);
m_CacheServerLauncherClass = m_JVMEnv->FindClass("com/Server/internal/ServerLauncher");
CheckForJNIException();
m_MainMethodID = m_JVMEnv->GetStaticMethodID(m_CacheServerLauncherClass, "main", "([Ljava/lang/String;)V");
CheckForJNIException();
}
void Server_JVMLauncher::StartServer_Server() {
if ( m_RunningJVMInstance->AttachCurrentThread((LPVOID *)&m_JVMEnv, NULL) ) {
std::cout << "Fail to attach the current thread " << std::endl;
}
jclass StringClass = m_JVMEnv->FindClass("java/lang/String");
int numOfArguments = (int)m_ServerArguments.size() + 2 ;
int argumentIndex = 0;
jobjectArray jargs = m_JVMEnv->NewObjectArray(numOfArguments, StringClass, NULL);
m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF("start"));
std::string strJavaClassPath = "-classpath=";
strJavaClassPath += "\"";
for ( std::size_t idx = 0; idx < m_listOfJars.size() - 1 ; idx++) {
strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[idx] + ";";
}
strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[m_listOfJars.size() - 1] ;
strJavaClassPath += "\"";
m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF(strJavaClassPath.c_str()));
for ( std::vector<std::string>::iterator iter = m_ServerArguments.begin(); iter != m_ServerArguments.end(); ++iter) {
std::string argument = *iter;
m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF(argument.c_str()));
}
m_JVMEnv->CallStaticVoidMethod(m_CacheServerLauncherClass, m_MainMethodID, jargs);
m_RunningJVMInstance->DestroyJavaVM();
std::cout << "I am done with launching java program" << std::endl;
CheckForJNIException();
}
void Server_JVMLauncher::StopServer_Server() {
jclass StringClass = m_JVMEnv->FindClass("java/lang/String");
int numOfArguments = 2 ;
jobjectArray jargs = m_JVMEnv->NewObjectArray(numOfArguments, StringClass, NULL);
m_JVMEnv->SetObjectArrayElement(jargs, 0, m_JVMEnv->NewStringUTF("stop"));
m_JVMEnv->SetObjectArrayElement(jargs, 1, m_JVMEnv->NewStringUTF("-dir=E:\\Avinash\\personal\\work\\CreateJvm\\Debug\\gfecs"));
m_JVMEnv->CallStaticVoidMethod(m_CacheServerLauncherClass, m_MainMethodID, jargs);
CheckForJNIException();
}
void Server_JVMLauncher::CheckForJNIException() {
jthrowable expt = m_JVMEnv->ExceptionOccurred();
if (expt != NULL) {
m_JVMEnv->ExceptionClear();
jmethodID toString = m_JVMEnv->GetMethodID(m_JVMEnv->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
jstring estring = (jstring) m_JVMEnv->CallObjectMethod(expt, toString);
jboolean isCopy;
std::string message = m_JVMEnv->GetStringUTFChars(estring, &isCopy);
throw JVMLauncherException(message);
}
}
int main( int argc, char **argv) {
try {
Server_JVMLauncher instanceServer_;
instanceServer_.LaunchJVM();
instanceServer_.StartServer_Server();
} catch (JVMLauncherException &excp ) {
std::cout << excp.what() << std::endl;
}
return 0;
}
Upvotes: 4
Views: 4237
Reputation: 121971
When you call CallStaticVoidMethod()
it does not create a child process but runs the Java main()
method in the calling thread, blocking the caller until it completes. If the Java program calls System.exit()
the process will exit immediately and will not return to the caller: don't call System.exit()
.
Upvotes: 3