/**********************************************************************
Copyright (c) 2005, 2009 IBM Corporation and others.
All rights reserved.   This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
$Id: hclaunch.c,v 1.2 2009/04/14 20:33:26 jwest Exp $
 
Contributors:
    IBM Corporation - initial implementation
**********************************************************************/

#include "hclaunch.h"
#include "launcher_common.h"
#include "RAComm.h"

#ifdef _DEBUG
FILE * trcFile;
#endif

/* Function declaration */
char* callJNIStringMethod(JNIEnv *jenv, jobject jobj, char *method);
long callJNILongMethod(JNIEnv *jenv, jobject jobj, char *method);
int callJNIIntMethod(JNIEnv *jenv, jobject jobj, char *method);
short callJNIShortMethod(JNIEnv *jenv, jobject jobj, char *method);
void callJNIVoidMethod(JNIEnv *jenv, jobject jobj, char *method);
jobject callJNIObjectMethod(JNIEnv *jenv, jobject jobj, char *method, int pos);
void cleanupChild(int sig);

/* we only need to keep track of the processes on platforms other than Windows. 
   The java code keeps track of processes on Windows platforms */ 

/* bugzilla 69642 start */ 
#ifndef _WIN32
#if defined(__linux__) && defined(__i386__)
	/* Bug 141033 */
#else
typedef struct child_process_list {
	PID childProcessID;		/* child process id of process launched */ 
	jobject processObject;  /* associated processObject */ 
	struct child_process_list *next; 
} child_process_list_t; 

child_process_list_t *child_processes = NULL; 

ra_critsec_t process_lock;

#endif /* __linux__ && __i386__ */
#endif /* _WIN32 */ 
/* bugzilla 69642 end */ 

/* Global reference to the JVM. */
static JavaVM *jvm = NULL; /* Bug 73453 */

/* Globals */
RemoteConsole_t console; /* User console for receiving input */
jobject exeObj;

/*
 * Called when JVM loads this DLL. This will register a signal handler for SIGCHLD on non-Windows platforms
 */

/* bugzilla 69642 -- do not #if 0 the code out */ 
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
#ifndef _WIN32
#ifndef _SOLARIS
#if defined(__linux__) && defined(__i386__)
	/* Bug 141033 */
#else
	struct sigaction sigActSIGCHLD;

	/* Cleanup our children when they exit */
	BZERO(&sigActSIGCHLD, sizeof(struct sigaction));
	sigActSIGCHLD.sa_handler = &cleanupChild;
	sigaction(SIGCHLD, &sigActSIGCHLD, NULL);

	ra_mutexCreate(&process_lock); 
#endif /* __linux__ && __i386__ */
#endif
#endif /* _WIN32 */

	return JNI_VERSION_1_2;
}


/* bugzilla 69642 start */ 
#ifndef _WIN32
#if defined(__linux__) && defined(__i386__)
	/* Bug 141033 */
#else
static void addProcessToList(PID childPID, JNIEnv *jenv, jobject jobj) {
	child_process_list_t *entry = (child_process_list_t *)ra_malloc(sizeof(child_process_list_t));
	if (entry == NULL) {
		return;
	}

	entry->childProcessID = childPID;
	entry->processObject = ENV(jenv)->NewGlobalRef(ENVPARM(jenv) jobj);
	ra_mutexEnter(&process_lock); 
	entry->next = child_processes;
	child_processes = entry; 
	ra_mutexExit(&process_lock); 
}

static jobject removeProcessFromList(PID childPID) {
	child_process_list_t *cur; 
	child_process_list_t *prev = NULL; 
	jobject returnObj = (int)NULL; 
	ra_mutexEnter(&process_lock); 
	cur = child_processes; 
	while (cur != NULL) {
		if (cur->childProcessID == childPID) {
			if (prev != NULL) {
				prev->next = cur->next;
			}
			else {
				child_processes = cur->next; 
			}
			returnObj = cur->processObject; 
			ra_free(cur); 
			break; 
		}
		prev = cur; 
		cur = cur->next; 
	}
	ra_mutexExit(&process_lock); 
	return returnObj; 
}
#endif /* __linux__ && __i386__ */
#endif /* _WIN32 */
/* bugzilla 69642 end */ 

/*
 * This is called by the ProcessExecutorImpl to launch a process. The process object is obtained from the executor through JNI.
 */
JNIEXPORT jint JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_startProcess0
	(JNIEnv *jenv, jobject jobj) {

	char *exe = NULL;
	char *cmdline = NULL;
	char *location = NULL;
	char *env = NULL;
	jclass jcls = (int)NULL;
	PID childPID = 0; /* The child process ID*/

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
    trcFile = fopen("startProcess.dbg", "w");
	fprintf(trcFile,"startProcess: start\n");
	fflush(trcFile);
	#ifdef MVS 
	#pragma convlit(resume)
	#endif
	#endif

	ENV(jenv)->GetJavaVM(ENVPARM(jenv) &jvm);

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);

	/* TODO will fix up the package name once it is finalized */
	if(jcls != (int)NULL) {
/*		jobject exeObj = NULL;  */
		jfieldID exeObjID = (int)NULL;
		jfieldID envObjID = (int)NULL;

		/* Find the IExecutableObject and get the exe, cmdline, and location for launch */
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		exeObjID = ENV(jenv)->GetFieldID(ENVPARM(jenv) jcls, "exeObj", "Lorg/eclipse/hyades/execution/core/IExecutableObject;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(exeObjID != (int)NULL) {
			exeObj = ENV(jenv)->GetObjectField(ENVPARM(jenv) jobj, exeObjID);
			if(exeObj != (int)NULL) {
#ifdef __OS400__
	#pragma convert(819) /* Bug 68899 */
#endif
				/* The returned strings are already in the native encoding */
				exe = callJNIStringMethod(jenv, exeObj, "getExe");
				cmdline = callJNIStringMethod(jenv, exeObj, "getCommandLine");
				location = callJNIStringMethod(jenv, exeObj, "getLocation");
#ifdef __OS400__
	#pragma convert(0) /* Bug 68899 */
#endif

				if(exe == NULL) {
					return ERROR_JNI_LAUNCH_EXE_NAME; /* Can't resolve the exe name */
				}
				if(cmdline == NULL) {
					return ERROR_JNI_LAUNCH_CMD_LINE; /* Can't resolve the cmd line string */
				}

                /* RKD: If the location is NULL, we should just run in teh default location  
				if(location == NULL) {
					return ERROR_JNI_LAUNCH_LOCATION; /* Can't resolve the location string 
				}
                */
			}
			else {
				return ERROR_JNI_LAUNCH_EXE_OBJ; /* Can't find the exe obj */
			}
		}
 		else {
			return ERROR_JNI_LAUNCH_EXE_OBJ_ID; /* Can't find the exe obj id */
		}

		/* Find the processEnvironment array to construct the env parameter */
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		envObjID = ENV(jenv)->GetFieldID(ENVPARM(jenv) jcls, "processEnvironment", "[Lorg/eclipse/hyades/execution/core/IOrderedProperty;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(envObjID != (int)NULL) {
			jobjectArray envObjArray = (int)NULL;

			envObjArray = (jobjectArray)ENV(jenv)->GetObjectField(ENVPARM(jenv) jobj, envObjID);
			if(envObjArray != (int)NULL) {
				jsize numEnv;
				

				numEnv = ENV(jenv)->GetArrayLength(ENVPARM(jenv) envObjArray);
				if(numEnv) {
					char *current;
					jsize i;
					jsize envBufferSize;

					envBufferSize=sizeof(char)  * numEnv * 256; /* Estimate a max 256 char per environment */
					env = (char*)malloc(envBufferSize); 
					current = env; /* Pointer that moves to navigate the env block */
					BZERO(env,envBufferSize);

					for(i = 0; i < numEnv; i++) {
						jclass propClass = (int)NULL;
						jstring envName = (int)NULL;
						jfieldID envNameID = (int)NULL;
						jfieldID envValueID = (int)NULL;
						jobject envObj = (int)NULL;
						jobject envValues = (int)NULL;

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
						propClass = ENV(jenv)->FindClass(ENVPARM(jenv) "org/eclipse/hyades/execution/core/impl/OrderedPropertyImpl");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
						if(propClass == (int)NULL) {
							return ERROR_JNI_LAUNCH_PROP_CLASSS; /* Can't find the property class */
					    }

					    envObj = ENV(jenv)->GetObjectArrayElement(ENVPARM(jenv) envObjArray, i); /* Get the object at index i */
					    if(envObj == (int)NULL) {
						    return ERROR_JNI_LAUNCH_ENV_OBJARRAY; /* Can't find the env obj array */
					    }

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
					    envNameID = ENV(jenv)->GetFieldID(ENVPARM(jenv) propClass, "name", "Ljava/lang/String;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
					    if(envNameID == (int)NULL) {
						    return ERROR_JNI_LAUNCH_ENV_NAME_ID; /* Can't find the env name id */
					    }

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
					    envValueID = ENV(jenv)->GetFieldID(ENVPARM(jenv) propClass, "values", "Ljava/util/Vector;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
					    if(envValueID == (int)NULL) {
						    return ERROR_JNI_LAUNCH_ENV_VALUE_ID; /* Can't find the env value id */
					    }

					    envName = (jstring)ENV(jenv)->GetObjectField(ENVPARM(jenv) envObj, envNameID);
					    if(envName == (int)NULL) {
							continue; /* Bug 143566 */
							/* return ERROR_JNI_LAUNCH_ENV_NAME; */ /* Can't find the env name */
					    }

					    envValues = ENV(jenv)->GetObjectField(ENVPARM(jenv) envObj, envValueID);
					    if(envValues == (int)NULL) {
						    return ERROR_JNI_LAUNCH_ENV_VALUE; /* Can't find the env value */
					    }


							if(envValues != (int)NULL) {
								jstring envStr;
								int j, size;
								char* envname;
								char* envvalue;

						    /* get the environment name */
							    envname = copyJavaStringToNative(jenv, envName);
								if(envname != NULL) {
									/* Ensure we have room in the buffer (include the '=' sign and null hense the 2) */
									while(current+strlen(envname)+2>env+envBufferSize) {
										char *tempEnv;
										jsize offset;
										jsize newSize=envBufferSize<<1;
										tempEnv=(char*)malloc(newSize);
	
										offset=current-env;
									
										memcpy(tempEnv, env, offset);
										current=tempEnv+offset;
										free(env);
										env=tempEnv;
										envBufferSize=newSize;
									}
									
									/* Copy the env name to the buffer */
									memcpy(current, envname, strlen(envname));
									current += strlen(envname);
#ifdef MVS
#pragma convlit(suspend)
#endif
									*current='=';
#ifdef MVS
#pragma convlit(resume)
#endif
									current += 1;
									ra_free(envname); /* Bug 103601 */
									envname=NULL;

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
									size = callJNIIntMethod(jenv, envValues, "size");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif

									/* Copy the values to the buffer */
									for(j = 0; j < size; j++) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
										envStr = (jstring)callJNIObjectMethod(jenv, envValues, "elementAt", j);
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif

										envvalue = copyJavaStringToNative(jenv, envStr);
										if(envvalue != NULL) {
											/* Ensure we have room in the buffer (include the path separator and double null terminator hense the 3) */
											while(current+strlen(envvalue)+3>env+envBufferSize) {
												char *tempEnv;
												jsize offset;
												jsize newSize=envBufferSize<<1;
												tempEnv=(char*)malloc(newSize);
		
												offset=current-env;
		
												memcpy(tempEnv, env, offset);
												current=tempEnv+offset;
												env=tempEnv;
												envBufferSize=newSize;
											}
		
											if(j > 0) {
	#ifdef MVS
	#pragma convlit(suspend)
	#endif
												*current=FILE_PATH_SEPARATOR;
	#ifdef MVS
	#pragma convlit(resume)
	#endif
												current++;
											}
		
									    memcpy(current, envvalue, strlen(envvalue));
									    current += strlen(envvalue);
		
											ra_free(envvalue); /* Bug 103601 */
											envvalue=NULL;
								    } /* envvalue != NULL */
								    else {
								    	/* envvalue == NULL */
								    }
									} /* for */
									*current='\0'; /* Finished appending all values */
									current++;
								} /* envname != NULL */
								else {
									/* envname == NULL */
								}
							}
						}
				    /* Copy an ending null when all properties are processed */
						*current='\0';
						current++;
					}
			}
			else {
				return ERROR_JNI_LAUNCH_ENV_OBJARRAY_ID; /* Can't find the env obj array id */
			}
		}
		else {
			return ERROR_JNI_LAUNCH_ENV_OBJ_ID; /* Can't find the env obj id */
		}
	}
	else {
		return ERROR_JNI_LAUNCH_EXE_CLS; /* Can't find the class */
	}

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile,"startProcess: launch process by calling hc_startProcess\n");
	fprintf(trcFile,"startProcess: exe = %s\n", exe);
	fprintf(trcFile,"startProcess: cmdline = %s\n", cmdline);
	fprintf(trcFile,"startProcess: location = %s\n", location);
	fflush(trcFile);
	#ifdef MVS                    
	#pragma convlit(resume)
	#endif
	#endif

	/* Attempt to launch process only if all required information exists. These are already checked above. */
	childPID = hc_startProcess(exe, cmdline, location, env, &console);

	/* bugzilla 69642 start */ 
#ifndef _WIN32
#if defined(__linux__) && defined(__i386__)
	/* Bug 141033 */
#else
	addProcessToList(childPID,jenv,jobj); 
#endif /* __linux__ && __i386__ */
#endif /* _WIN32 */
	/* bugzilla 69642 end */ 

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile,"startProcess: started process - pid = %d\n", childPID);
	fflush(trcFile);
	fclose(trcFile);
	#ifdef MVS                  
	#pragma convlit(resume)
	#endif
	#endif

	return childPID;
}

/*
 * This is called by the ProcessExecutorImpl to kill a process. The pid to be kill is obtained from the executor through JNI.
 */
JNIEXPORT void JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_killProcess0
	(JNIEnv *jenv, jobject jobj) {

	jclass jcls = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);

	if(jcls != (int)NULL) {
		jfieldID pidField = (int)NULL;

		/* Find the IExecutableObject and get the exe, cmdline, and location for launch */
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		pidField = ENV(jenv)->GetFieldID(ENVPARM(jenv) jcls, "pid", "I");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(pidField != (int)NULL) {
			jint pid = 0;

			pid = ENV(jenv)->GetIntField(ENVPARM(jenv) jobj, pidField);
			if(pid != 0) {
				hc_killProcess(pid);
			}
		}
	}

	return;
}

/*
 * This is called by the ProcessExecutorImpl to write a byte to the process's stdin stream.
 */
JNIEXPORT void JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_writeToProcess0
	(JNIEnv *jenv, jobject jobj, jchar c) {

	hc_writeFileChar(console.in, (char)c);

	return;
}

/*
 * This is called by the ProcessExecutorImpl to read a byte from the process's stdout stream.
 */
JNIEXPORT jint JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_readFromProcessOutput0
	(JNIEnv *jenv, jobject jobj) {
	char c[1];

	if(hc_readFile(console.out, c, 1) <= 0) {
		return (int)-1;
	}

	return (int)c[0];
}

/*
 * This is called by the ProcessExecutorImpl to read a byte from the process's stderr stream.
 */
JNIEXPORT jint JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_readFromProcessError0
	(JNIEnv *jenv, jobject jobj) {
	char c[1];

	if(hc_readFile(console.err, c, 1) <= 0) {
		return (int)-1;
	}

	return (int)c[0];
}


/*
 * This is called by the ProcessExecutorImpl to get the current process status.
 */
JNIEXPORT jint JNICALL Java_org_eclipse_hyades_execution_core_impl_ProcessExecutorImpl_getProcessStatus0
	(JNIEnv *jenv, jobject jobj, jint pid) {

	return hc_getProcessStatus(pid);
}


/*
 * This is called by the ExecutionEnvironmentImpl to query the default system properties.
 */
JNIEXPORT jobjectArray JNICALL Java_org_eclipse_hyades_execution_core_impl_ExecutionEnvironmentImpl_getNativeSystemEnvironment0
	(JNIEnv *jenv, jobject jobj) {
	char sep[] = "=";
	char *envName;
	char *envValue;
	int index = 0;
	jclass envClass = (int)NULL;
	jclass strClass = (int)NULL;
	jobjectArray envArray = (int)NULL;
	jmethodID envCtor = (int)NULL;
	jmethodID appendValueID = (int)NULL;
	jfieldID envNameID = (int)NULL;
	jfieldID envValuesID = (int)NULL;
	jobject envObj = (int)NULL;
	jstring strObj = (int)NULL;
	void* envStr = NULL;
	int envOffset = 0;

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
    trcFile = fopen("getenv.dbg", "w");
	fprintf(trcFile,"getNativeSystemEnvironment: start\n");
	fflush(trcFile);
	#ifdef MVS      
	#pragma convlit(resume)
	#endif
	#endif

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	envClass = ENV(jenv)->FindClass(ENVPARM(jenv) "org/eclipse/hyades/execution/core/impl/OrderedPropertyImpl");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(envClass == (int)NULL) {
		return (int)NULL;
	}

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	strClass = ENV(jenv)->FindClass(ENVPARM(jenv) "java/lang/String");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(strClass == (int)NULL) {
		return (int)NULL;
	}

	envArray = ENV(jenv)->NewObjectArray(ENVPARM(jenv) MAX_ENV, envClass, (int)NULL);
	if(envArray == (int)NULL) {
		return (int)NULL;
	}

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	envCtor = ENV(jenv)->GetMethodID(ENVPARM(jenv) envClass, "<init>", "()V");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(envCtor == (int)NULL) {
		return (int)NULL;
	}

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	appendValueID = ENV(jenv)->GetMethodID(ENVPARM(jenv) envClass, "appendValue", "(Ljava/lang/Object;)V");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(appendValueID == (int)NULL) {
		return (int)NULL;
	}

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	envNameID = ENV(jenv)->GetFieldID(ENVPARM(jenv) envClass, "name", "Ljava/lang/String;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(envNameID == (int)NULL) {
		return (int)NULL;
	}

#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
	envValuesID = ENV(jenv)->GetFieldID(ENVPARM(jenv) envClass, "values", "Ljava/util/Vector;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
	if(envValuesID == (int)NULL) {
		return (int)NULL;
	}

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile,"getNativeSystemEnvironment: about to get environment\n");
	fflush(trcFile);
	#ifdef MVS                    
	#pragma convlit(resume)
	#endif
	#endif

	/* Get the system environment */
	envStr = hc_getEnvironment();

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile,"getNativeSystemEnvironment: got environment %p\n", envStr);
	fflush(trcFile);
	#ifdef MVS                    
	#pragma convlit(resume)
	#endif
	#endif

	while(envOffset >= 0) {
		/* Get the next name-value pair */
		envOffset = hc_getEnvironmentVariable(envStr, envOffset, &envName, &envValue);

		#ifdef _DEBUG
		#ifdef MVS                    
		#pragma convlit(suspend)
		#endif
		fprintf(trcFile,"getNativeSystemEnvironment: next envOffset = %d \n", envOffset);
		fflush(trcFile);
		#ifdef MVS                    
		#pragma convlit(resume)
		#endif
		#endif

		if(envName != NULL) {

			/* Create the OrderedPropertyImpl object */
			envObj = ENV(jenv)->NewObject(ENVPARM(jenv) envClass, envCtor);

			/* Create a String object to store the property name and set it to the OrderedPropertyImpl object */
			strObj = ENV(jenv)->NewStringUTF(ENVPARM(jenv) envName);
			ENV(jenv)->SetObjectField(ENVPARM(jenv) envObj, envNameID, strObj);

			/* Create a String object to store the property value and append it to the OrderedPropertyImpl object */
			if(envValue == NULL || *envValue == '\0') {
				strObj = ENV(jenv)->NewStringUTF(ENVPARM(jenv) "\0"); /* Bug 68899 */
			}
			else {
				strObj = ENV(jenv)->NewStringUTF(ENVPARM(jenv) envValue);	    
			}
			ENV(jenv)->CallVoidMethod(ENVPARM(jenv) envObj, appendValueID, strObj);

			/* Add the completed OrderedPropertyImpl object to the array */
			ENV(jenv)->SetObjectArrayElement(ENVPARM(jenv) envArray, index, envObj);

			/* free the temporary space for the name and value */
			free(envName);
			free(envValue);

			index++;
		}
	}

	#ifdef _DEBUG
	#ifdef MVS                    
	#pragma convlit(suspend)
	#endif
	fprintf(trcFile,"getNativeSystemEnvironment: %d environment variables were found\n", index);
	fflush(trcFile);
	fclose(trcFile);
	#ifdef MVS          
	#pragma convlit(resume)
	#endif
	#endif

	return envArray;
}


/*
 * JNI helper functions
 */

/* Call the CallObjectMethod with object type String and no arg */
char* callJNIStringMethod(JNIEnv *jenv, jobject jobj, char *method) {
	char *rc = NULL;
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "()Ljava/lang/String;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
            jstring result=(jstring)ENV(jenv)->CallObjectMethod(ENVPARM(jenv) jobj, jmethod);
            if(result != (int)NULL) {
			    rc = copyJavaStringToNative(jenv, result);
            }
		}
	}

	return rc;
}

/* Call the CallLongMethod with object type long and no arg */
long callJNILongMethod(JNIEnv *jenv, jobject jobj, char *method) {
	long rc = 0;
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "()J");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
#if defined (__OS400__)
			rc = (ENV(jenv)->CallLongMethod(ENVPARM(jenv) jobj, jmethod)).ll;
#else
			rc = (long)(ENV(jenv)->CallLongMethod(ENVPARM(jenv) jobj, jmethod));
#endif
		}
	}

	return rc;
}

/* Call the CallIntMethod with object type int and no arg */
int callJNIIntMethod(JNIEnv *jenv, jobject jobj, char *method) {
	int rc = 0;
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "()I");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
			rc = (int)(ENV(jenv)->CallIntMethod(ENVPARM(jenv) jobj, jmethod));
		}
	}

	return rc;
}

/* Call the CallShortMethod with object type short and no arg */
short callJNIShortMethod(JNIEnv *jenv, jobject jobj, char *method) {
	short rc = 0;
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "()S");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
			rc = (short)(ENV(jenv)->CallShortMethod(ENVPARM(jenv) jobj, jmethod));
		}
	}

	return rc;
}

/* Call the CallVoidMethod with object type void and no arg */
void callJNIVoidMethod(JNIEnv *jenv, jobject jobj, char *method) {
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "()V");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
			ENV(jenv)->CallVoidMethod(ENVPARM(jenv) jobj, jmethod);
		}
	}
}

/* Call the CallObjectMethod with object type Object and 1 arg */
jobject callJNIObjectMethod(JNIEnv *jenv, jobject jobj, char *method, int pos) {
	jobject rc = 0;
	jclass jcls = (int)NULL;
	jmethodID jmethod = (int)NULL;

	jcls = ENV(jenv)->GetObjectClass(ENVPARM(jenv) jobj);
	if(jcls != (int)NULL) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
		jmethod = ENV(jenv)->GetMethodID(ENVPARM(jenv) jcls, method, "(I)Ljava/lang/Object;");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		if(jmethod != (int)NULL) {
			rc = (jobject)(ENV(jenv)->CallObjectMethod(ENVPARM(jenv) jobj, jmethod, pos));
		}
	}

	return rc;
}

/*
 * A signal handler routine. Called when a child exits.
 */
/* bugzilla 69642 start */ 
void cleanupChild(int sig) {
#ifndef _WIN32
#if defined(__linux__) && defined(__i386__)
	/* Bug 141033 */
#else
	JNIEnv *jenv;
	int result, status;
	PID childPID; 
	jobject processObj; 

	/* Bug 73453: If somehow the jvm is not initialized, skip this function */
	if(jvm == NULL) {
		return;
	}

	childPID = wait(&status); 
	processObj = removeProcessFromList(childPID); 

	/* Attach the current thread to the JVM */
#if defined __cplusplus && defined _HPUX
	result = ENV(jvm)->AttachCurrentThread((void**)&jenv, NULL);
#else
	result = (*jvm)->AttachCurrentThread(jvm, (void**)&jenv, NULL);
#endif

	if (processObj != (int)NULL) {
		if(result == 0) {
#ifdef __OS400__
#pragma convert(819) /* Bug 68899 */
#endif
			callJNIVoidMethod(jenv, processObj, "processExited");
#ifdef __OS400__
#pragma convert(0) /* Bug 68899 */
#endif
		}
		ENV(jenv)->DeleteGlobalRef(ENVPARM(jenv) processObj);
	}

#endif /* __linux__ && __i386__ */
#endif /* _WIN32 */

	return;
}
/* bugzilla 69642 end */ 
