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

_Ndugu_Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

_Ndugu_Author Commented:
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
0
_Ndugu_Author Commented:
Problem solved.

Removed Attach and Detach Threads.

In ClassLoader constructor, call the following methods:

1. CreateJavaVM  
2. FindClass
3. GetMethodID
Can only call 1) once per process, even though calls are sequential.  
I found that I can only call 2&3) once per process otherwise classpath got messed up.

then just call the static method multiple times, don't bother about the FindClass and GetMethodID - values already set  in the first call.

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.