Link to home
Start Free TrialLog in
Avatar of _Ndugu_
_Ndugu_

asked on

How do i make multiple sequential calls to jvm from same process

Hi I have 2 questions

1. I have tried to make multiple calls to jni_CreateJavaJVM and DestroyJVM within a C function.

This only works when I call the C function several times from a shellscript.  

I want to call the function several times from a C process though, but the CreateJVM fails with the error:
the Java HotSpot Server VM does not support Signal-chaining.  (I believe there's a known problem unloading the JVM when DestroyJVM is called) so...

I have now made the JNIEnv var static and initialised it to NULL.  I test to see if it's null now before creating the JVM - it gets past this step now but fails at NewStringUTF.... any ideas?  see attached code.  (I have commented and uncommented DestroyJVM but it's made no difference)

here's the backtrace:
( 0)  0xd6951894   report_and_die__7VMErrorFv + 0x17c  [/opt/java1.4/jre/lib/PA_RISC2.0/server/libjvm.sl]
( 1)  0xd6852614   JVM_handle_hpux_signal__Q2_2os4HpuxSFiP9__siginfoPvT1 + 0x2bc  [/opt/java1.4/jre/lib/PA_RISC2.0/server/libjvm.sl]
( 2)  0xd684dad4   signalHandler__Q2_2os4HpuxSFiP9__siginfoPv + 0x4c  [/opt/java1.4/jre/lib/PA_RISC2.0/server/libjvm.sl]
( 3)  0xc020bfe0   _sigreturn  [/usr/lib/libc.2]
( 4)  0xd66fbe34   jni_NewStringUTF__FP7JNIEnv_PCc + 0x64  [/opt/java1.4/jre/lib/PA_RISC2.0/server/libjvm.sl]
( 5)  0xc960c7b4   callStaticInvokeMethod__11CJavaLoaderFPcN41 + 0xaac  [/oo_dgfqausr2/JavaCAPI/CAPI_svnJVM/lib/libjar.sl]
( 6)  0xc9609344   invoke + 0x1ae0  [/oo_dgfqausr2/JavaCAPI/CAPI_svnJVM/lib/libjar.sl]
( 7)  0xc374b020   getBundlePlans + 0x4cc  [../libvc.sl]
( 8)  0x00006710   call_getBundlePlans__Fv + 0xd0  [./testVCCAPI]
( 9)  0x00009bd0   main + 0x2a4  [./testVCCAPI]
(10)  0xc01434d0   _start + 0xc0  [/usr/lib/libc.2]
(11)  0x000052f0   $START$ + 0x178  [./testVCCAPI]
runVCTests.sh[21]: 1756 Abort(coredump)


2. - my second question is ... how can I catch the JVM errors?... my catch(...) doesn't seem to catch any of them and the jvm crashes

Thanks in advance
Ndugu
char* callStaticJavaMethod(char* className, char* callMethodName, char * in_classpath, char *jvmOptions, char* xmlArg)
        throw(JavaException)
 
{
  char* response = NULL;  
  const char *resultCStr;
  
  char* newString = NULL;
  char classpath[_MAX_CLASSPATH_LEN_+1];
  
  bool argStrAllocated = false;
  jstring argStr;   //Defined here so it can be freed by the catch if required.
  
  bool jvmLoaded = false;
 
   cout  << endl
         << endl
         << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << endl
         << endl
         << "[" << getDateTime() << "] CJavaLoader::callStaticInvokeMethod(\""
         << className << "\", \"" << callMethodName << "\", \"" << xmlArg << "\") - Started"
         << endl;
 
   char methodName[] = "callStaticInvokeMethod(char*, char*, char*, char *, char*)";
 
 
/******** JNI specific *************/
 
   static JNIEnv *jniEnv = NULL;  //pointer to native method interface 
   JavaVM *jvm = NULL;   // denotes a Java VM 
   JavaVMInitArgs vm_args;
   JavaVMOption *options = NULL;
   jint res;
   vm_args.version = JNI_VERSION_1_4;
 
/******** JNI specific *************/
   char* umclasspath = NULL;
 
   try {
		int inumOptions =0;
 
 
		if (xmlArg == NULL || strlen(xmlArg) < 1){
			throw JavaException(_JVM_NOT_INITIALISED_, (char*)"");
		}
 
 
		if ( jniEnv == NULL){
		
			cout << "jniEnv is NULL"<< endl << endl;
			cout.flush();
		
			if (!(jvmOptions && in_classpath && *jvmOptions && *in_classpath)){
				cerr << "jvm.runtime.options and jvm.classpath must be set in properties file " << endl;
				throw JavaException(_JVM_NOT_INITIALISED_, (char*)"ERROR creating JVM. xmlArg is null");
			}	
	
			// intialise jvm
			
			char *copy =  new char[strlen(jvmOptions) + 1];
			memset(copy, '\0', strlen(jvmOptions) + 1);
			strncpy(copy, jvmOptions, strlen(jvmOptions));
			
			inumOptions =getNumJVMOptions(copy)+1; // for the classpath
			
		 	if (copy) delete[] copy;	
			copy = NULL;
			
			cout << "==================creating options===================="<< endl << endl;
			options = new JavaVMOption[inumOptions]; 
	
			int optionCount = 0; 
	
			options[optionCount].optionString = in_classpath;
	
	        char *token;
	
	        copy = new char[strlen(jvmOptions) + 1]; 
			memset(copy, '\0', strlen(jvmOptions) + 1);
			strncpy(copy, jvmOptions, strlen(jvmOptions));
	
	       	token = strtok(copy, " ");   //Assumes ' ' as delimiter
	
	       	while (token && *token) {
	          		options[++optionCount].optionString = token;		
	          		token = strtok(NULL, " ");
	       	}
	
	        if (copy) delete [] copy;	
	        
	        copy = NULL;
			token = NULL; 
			
	        vm_args.options = options;
	        vm_args.nOptions = inumOptions;
	        vm_args.ignoreUnrecognized = JNI_TRUE;
	
			cout << "vm_args.nOptions = " << vm_args.nOptions << endl;
	
	        for (int i = 0; i < vm_args.nOptions ; i++){
	             cout << "option["<<i << "] = [" << vm_args.options[i].optionString << "]" << endl ;
	        }
	
	
			/******************** CREATE JVM ********************/
	    	res = JNI_CreateJavaVM(&jvm, (void **) &jniEnv,&vm_args);
		
			if (ExceptionRaised(jniEnv) || res != 0){
		     //	if (res != 0) {
		       		cerr << "JNI_CreateJavaVM failed %d\n" << res << "." << endl;
				delete [] options;
				throw JavaException(_JVM_NOT_INITIALISED_, (char*)"ERROR creating JVM");
		     }
		     
		    cout << "==================deleting options===================="<< endl << endl;
			cout.flush();
			
			if (options) delete [] options;  
			
			jvmLoaded = true;		     		
		}
		
		argStrAllocated = false;
		
		cout << "NewStringUTF"<< endl << endl;
		cout.flush();
		
		argStr = jniEnv->NewStringUTF(xmlArg);
		
		if (argStr == NULL)
			throw JavaException(_JVM_NOT_INITIALISED_, (char*)"ERROR creating UTF String"); 
		
		if (ExceptionRaised(jniEnv)){
				//if (argStr == 0){
					LOG_OUT << "ERROR creating JVM, OUT OF MEMORY"<< endl;
					throw JavaException(_JVM_NOT_INITIALISED_, (char*)"ERROR creating JVM, OUT OF MEMORY"); 
		}
		
		argStrAllocated = true;
 
		cout << "FindClass"<< endl << endl;
		cout.flush();
		
		jclass callingClass = jniEnv->FindClass(className);
		if (ExceptionRaised(jniEnv)){
				//if (callingClass == 0) {   //Unable to find the class
				      LOG_OUT  << "Unable to find the class [" << className
				               << "] along the classpath [" << classpath << "]" << endl;
				     
				      throw JavaException(_CLASS_NOT_FOUND_, (char*)"Class not found");
		}
		
		cout << "GetStaticMethodID"<< endl << endl;
		cout.flush();		
		
		jmethodID methodID = jniEnv->GetStaticMethodID(callingClass, callMethodName, "(Ljava/lang/String;)Ljava/lang/String;");
		if (ExceptionRaised(jniEnv)){
			 //if (methodID == 0) {  //Method does not exist in the specified class
			
			      LOG_OUT  << "The method [" << callMethodName << "] does not exist in class ["
			               << className << "]" << endl;
			      throw JavaException(_METHOD_NOT_FOUND_, (char*)"Method not found");
		}
			
		cout << "CallStaticObjectMethod"<< endl << endl;
		cout.flush();	
			
		jstring resultJStr = (jstring)jniEnv->CallStaticObjectMethod(callingClass, methodID, argStr);
		cout << "after CallStaticObjectMethod" << endl;
		if (ExceptionRaised(jniEnv)){
	                      LOG_OUT  << "ERROR invoking java method " << callMethodName << " in JVM " << endl;
	                      throw JavaException(_GENERIC_ERROR, (char*)"ERROR invoking java method in JVM");
	    }
		
		//Deallocate the argument string
		jniEnv->DeleteLocalRef(argStr);
	    if (ExceptionRaised(jniEnv))
		{
	                      LOG_OUT  << "ERROR deleting jstring in JVM " << endl;
	                      throw JavaException(_GENERIC_ERROR, (char*)"ERROR deleting jstring in JVM");
	                
		}
	
		jboolean isCopy;
			
		resultCStr = jniEnv->GetStringUTFChars(resultJStr, &isCopy);
 
	    if (isCopy == JNI_TRUE){
 
		    cout <<" resultJStr [" << resultJStr << "]" << endl;		
		    cout <<" resultCStr [" << resultCStr << "]" << endl;		
 
        	response = new char[strlen(resultCStr)+1];
 
      		memset(response, '\0', strlen(resultCStr)+1);
      		strncpy(response, resultCStr, strlen(resultCStr));
 
			jniEnv->ReleaseStringUTFChars(resultJStr, resultCStr);
 
			resultCStr = NULL;			
		}
		else{
			
			LOG_OUT <<"ERROR. No xmlString returned from service" << endl;
			throw JavaException(_GENERIC_ERROR, (char*)"ERROR. No xmlString returned from service");
		}
 
		jniEnv->DeleteLocalRef(resultJStr);
 
        if (ExceptionRaised(jniEnv)){
                 LOG_OUT  << "ERROR deleting jstring in JVM " << endl;
                 throw JavaException(_GENERIC_ERROR, (char*)"ERROR deleting jstring in JVM");
        }
   }
/*   catch(JavaException e){
	
   }*/
   catch (...) {
 
	    LOG_OUT  << endl << endl
	               << "XXXXXXXXXXXXXXXXXX" << endl
	               << "\tException caught" << endl << "XXXXXXXXXXXXXXXXXX"
	               << endl << endl;
	
	    if (!response) 
	        response = new char[strlen(_ERROR_IN_JAVA_CALL_)+1];
	
	    memset(response, '\0', strlen(_ERROR_IN_JAVA_CALL_)+1);
	    strncpy(response, _ERROR_IN_JAVA_CALL_, strlen(_ERROR_IN_JAVA_CALL_));
	 
	    LOG_OUT  << "Java call finished." << endl
	               << "\tResult was [" << _ERROR_IN_JAVA_CALL_ << "]" << endl
	               << endl
	               << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << endl
	               << endl;
 
		if (resultCStr)
			resultCStr = NULL;
	
		if (argStrAllocated)
			jniEnv->DeleteLocalRef(argStr);
			
		if (jvmLoaded){
				   if (jvm->DestroyJavaVM() != 0){
	                      LOG_OUT  << "DestroyJVM method did not unload the JVM. Contact Development" << endl;
	                      throw JavaException(_GENERIC_ERROR, (char*)"ERROR deleting JVM ");
	   				}
	   	}
			
   }
   
   /******************** DESTROY JVM ********************/
   if (jvmLoaded){
	   if (jvm->DestroyJavaVM() != 0){
	                      LOG_OUT  << "DestroyJVM method did not unload the JVM. Contact Development" << endl;
	                      throw JavaException(_GENERIC_ERROR, (char*)"ERROR deleting JVM ");
	   }
   }
 
		
	LOG_OUT  << "Java call finished." << endl
		                   << "\tResult was [" << response << "]" << endl
		                   << endl
		                   << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << endl
		                   << endl;
 
 
   return response;
}

Open in new window

Avatar of _Ndugu_
_Ndugu_

ASKER

Hi I've figured out it's not possible (or at least not easy) to call JNI_CreateJavaJVM multiple times from the same process.

Here's what I've done... put JNIEnv, JavaVM etc.. into a C++ class ClassLoader

I declare this class as static and intialise it to null from my C function.

static ClassLoader classLoader = NULL;

if (classLoader== NULL)
    classLoader = new ClassLoader();

Then for all processes (not just the one that grabbed ClassLoader first):
AttachCurrentThread
--call findClass, callstaticMethod etc
DetachCurrentThread after callstaticMethod.

The DestroyJVM call is in the ClassLoader destructor.

---
This now creates the JVM and I can trace through the java calls, but now I'm having problems with the java methods parsing some xml ........ this is the error:

Exception [java.lang.Exception: javax.xml.parsers.DocumentBuilder cannot be created or instantiated: Provider weblogic.xml.jaxp.RegistryDocumentBuilderFactory not found

I can see this class in a weblogic.jar file  that's in the same location as the jar that's calling it?

should I post this elsewhere now the previous problem is sorted or is it somewhat related?

thanks
ASKER CERTIFIED SOLUTION
Avatar of _Ndugu_
_Ndugu_

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial