Ejemplo n.º 1
0
bool GetJREPathFromEnvVars(char* path, size_t pathSize, const char* arch)
{
	bool found = false;

	static const size_t possLoc_sizeMax = 32;
	char* possLoc[possLoc_sizeMax];
	size_t possLoc_i = 0;

	possLoc[possLoc_i++] = util_allocStrCpy("JAVA_HOME");
	possLoc[possLoc_i++] = util_allocStrCpy("JDK_HOME");
	possLoc[possLoc_i++] = util_allocStrCpy("JRE_HOME");

	size_t l;
	for (l=0; l < possLoc_i; ++l) {
		const char* envPath = getenv(possLoc[l]);
		if (envPath != NULL) {
			found = GetJREPathFromBase(path, pathSize, envPath, arch);
			if (found) {
				simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in env var \"%s\"!", possLoc[l]);
				goto locSearchEnd;
			} else {
				simpleLog_logL(LOG_LEVEL_WARNING, "Unusable JRE from env var \"%s\"=\"%s\"!", possLoc[l], envPath);
			}
		}
	}
 locSearchEnd:

	// cleanup
	for (l=0; l < possLoc_i; ++l) {
		free(possLoc[l]);
		possLoc[l] = NULL;
	}

	return found;
}
Ejemplo n.º 2
0
/**
 * Creates the Java library path.
 * -> where native shared libraries are searched
 *
 * It will consist of the following:
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/lib/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/lib/
 */
static bool java_createNativeLibsPath(char* libraryPath, const size_t libraryPath_sizeMax) {

	// {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/
	const char* const dd_r =
			callback->AIInterface_Info_getValueByKey(interfaceId,
			AI_INTERFACE_PROPERTY_DATA_DIR);
	if (dd_r == NULL) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Unable to find read-only data-dir.");
		return false;
	} else {
		STRCPYS(libraryPath, libraryPath_sizeMax, dd_r);
	}

	// {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/lib/
	char* dd_lib_r = callback->DataDirs_allocatePath(interfaceId,
			NATIVE_LIBS_DIR, false, false, true, false);
	if (dd_lib_r == NULL) {
		simpleLog_logL(SIMPLELOG_LEVEL_NORMAL,
				"Unable to find read-only native libs data-dir (optional): %s",
				NATIVE_LIBS_DIR);
	} else {
		STRCATS(libraryPath, libraryPath_sizeMax, ENTRY_DELIM);
		STRCATS(libraryPath, libraryPath_sizeMax, dd_lib_r);
		FREE(dd_lib_r);
	}

	// {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/
	const char* const dd_r_common =
			callback->AIInterface_Info_getValueByKey(interfaceId,
			AI_INTERFACE_PROPERTY_DATA_DIR_COMMON);
	if (dd_r_common == NULL || !util_fileExists(dd_r_common)) {
		simpleLog_logL(SIMPLELOG_LEVEL_NORMAL,
				"Unable to find common read-only data-dir (optional).");
	} else {
		STRCATS(libraryPath, libraryPath_sizeMax, ENTRY_DELIM);
		STRCATS(libraryPath, libraryPath_sizeMax, dd_r_common);
	}

	// {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/lib/
	if (dd_r_common != NULL) {
		char* dd_lib_r_common = callback->DataDirs_allocatePath(interfaceId,
			NATIVE_LIBS_DIR, false, false, true, true);
		if (dd_lib_r_common == NULL || !util_fileExists(dd_lib_r_common)) {
			simpleLog_logL(SIMPLELOG_LEVEL_NORMAL,
					"Unable to find common read-only native libs data-dir (optional).");
		} else {
			STRCATS(libraryPath, libraryPath_sizeMax, ENTRY_DELIM);
			STRCATS(libraryPath, libraryPath_sizeMax, dd_lib_r_common);
			FREE(dd_lib_r_common);
		}
	}

	return true;
}
Ejemplo n.º 3
0
void simpleLog_init(const char* _logFileName, bool _useTimeStamps,
		int _logLevel, bool append) {

	if (_logFileName != NULL) {
		// NOTE: this causes a memory leack, as it is never freed.
		// but it is used till the end of the applications runtime anyway
		// -> no problem
		logFileName = util_allocStrCpy(_logFileName);
	
		// delete the logFile, and try writing to it
		FILE* file = NULL;
		if (logFileName != NULL) {
			if (append) {
				file = FOPEN(logFileName, "a");
			} else {
				file = FOPEN(logFileName, "w");
			}
		}
		if (file != NULL) {
			// make the file empty
			FPRINTF(file, "%s", "");
			fclose(file);
			file = NULL;
		} else {
			// report the error to stderr
			FPRINTF(stderr, "Failed writing to the log file \"%s\".\n%s",
					logFileName, "We will continue logging to stdout.");
		}

		// make sure the dir of the log file exists
		char* logFileDir = util_allocStrCpy(logFileName);
		if (!util_getParentDir(logFileDir)) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to evaluate the parent dir of the config file: %s",
					logFileName);
		} else if (!util_makeDir(logFileDir, true)) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to create the parent dir of the config file: %s",
					logFileDir);
		}
		free(logFileDir);
	} else {
		simpleLog_logL(-1, "No log file name supplied -> logging to stdout and stderr",
			useTimeStamps ? "yes" : "no", logLevel);
		logFileName = NULL;
	}

	useTimeStamps = _useTimeStamps;
	logLevel = _logLevel;

	simpleLog_logL(-1, "[logging started (time-stamps: %s / logLevel: %i)]",
			useTimeStamps ? "yes" : "no", logLevel);
}
Ejemplo n.º 4
0
bool java_unloadJNIEnv() {

	if (g_jvm != NULL) {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "JVM: Unloading ...");

		//JNIEnv* env = java_getJNIEnv();

		// We have to be the ONLY running thread (native and Java)
		// this may not help, but will not hurt either
		//jint res = (*g_jvm)->AttachCurrentThreadAsDaemon(g_jvm,
		//		(void**) &g_jniEnv, NULL);
		//res = jvm->AttachCurrentThread((void**) & jniEnv, NULL);
		/*if (res < 0 || (*g_jniEnv)->ExceptionCheck(g_jniEnv)) {
			if ((*g_jniEnv)->ExceptionCheck(g_jniEnv)) {
				(*g_jniEnv)->ExceptionDescribe(g_jniEnv);
			}
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"JVM: Can not Attach to the current thread: %i - %s",
					res, jniUtil_getJniRetValDescription(res));
			return false;
		}*/

		const jint res = (*g_jvm)->DetachCurrentThread(g_jvm);
		if (res != 0) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"JVM: Failed detaching current thread: %i - %s",
					res, jniUtil_getJniRetValDescription(res));
			return false;
		}

		// Never destroy the JVM, because it can not be created again
		// for the same thread; would allways fail with return value -1,
		// which would be a problem when using the /aicontrol or /aireload
		// commands on java AIs
		/*res = (*g_jvm)->DestroyJavaVM(g_jvm);
		if (res != 0) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"JVM: Failed destroying: %i - %s",
					res, jniUtil_getJniRetValDescription(res));
			return false;
		} else {
			simpleLog_logL(SIMPLELOG_LEVEL_NORMAL,
					"JVM: Successfully destroyed");
			g_jvm = NULL;
		}*/
		java_establishSpringEnv();
	}

	return true;
}
Ejemplo n.º 5
0
static JNIEnv* java_reattachCurrentThread() {

	JNIEnv* env = NULL;

	simpleLog_logL(SIMPLELOG_LEVEL_FINEST, "Reattaching current thread...");
	//const jint res = (*g_jvm)->AttachCurrentThreadAsDaemon(g_jvm, (void**) &env, NULL);
	const jint res = (*g_jvm)->AttachCurrentThread(g_jvm, (void**) &env, NULL);
	if (res != 0) {
		env = NULL;
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed attaching JVM to current thread(2): %i - %s",
				res, jniUtil_getJniRetValDescription(res));
	}

	return env;
}
Ejemplo n.º 6
0
static bool GetJREPathWhichJava(char* path, size_t pathSize, const char* arch)
{
	static const char* suf = "/bin/java";
	const size_t suf_size = strlen(suf);

	bool found = false;

	// execute
	FILE* cmd_fp = popen("which java  | sed 's/[\\n\\r]/K/g'", "r");
	if (cmd_fp == NULL) {
		return found;
	}

	// parse results
	static const size_t line_sizeMax = 512;
	char line[line_sizeMax];
	if (fgets(line, line_sizeMax, cmd_fp)) {
		if (*line == '/') { // -> absolute path
			size_t line_size = strlen(line);
			if (*(line+line_size-1) == '\n') {
				// remove trailing '\n'
				*(line+line_size-1) = '\0';
				line_size--;
			}

			simpleLog_logL(SIMPLELOG_LEVEL_FINEST,
					"which line \"%s\"!", line);

			if (line_size > suf_size
					&& strcmp(line+(line_size-suf_size), suf) == 0) {
				// line ends with suf
				simpleLog_logL(SIMPLELOG_LEVEL_FINER,
						"JRE found with `which java`!");
				// remove suf
				*(line+(line_size-suf_size)) = '\0';
				found = GetJREPathFromBase(path, pathSize, line, arch);
			}
		}
	}
	pclose(cmd_fp);

	return found;
}
Ejemplo n.º 7
0
bool java_initSkirmishAIClass(
		const char* const shortName,
		const char* const version,
		const char* const className,
		int skirmishAIId) {

	bool success = false;

	// see if an AI for className is instantiated already
	size_t sai;
	size_t firstFree = skirmishAiImpl_size;
	for (sai = 0; sai < skirmishAiImpl_size; ++sai) {
		if (skirmishAiImpl_className[sai] == NULL) {
			firstFree = sai;
		} else if (strcmp(skirmishAiImpl_className[sai], className) == 0) {
			break;
		}
	}
	// sai is now either the instantiated one, or a free one

	// instantiate AI (if needed)
	if (skirmishAiImpl_className[sai] == NULL) {
		sai = firstFree;
		java_establishJavaEnv();
		JNIEnv* env = java_getJNIEnv();

		jobject    instance    = NULL;
		jobject    classLoader = NULL;

		success = java_loadSkirmishAI(env, shortName, version, className,
				&(instance), &(classLoader));
		java_establishSpringEnv();

		if (success) {
			skirmishAiImpl_instance[sai]    = instance;
			skirmishAiImpl_classLoader[sai] = classLoader;
			skirmishAiImpl_className[sai]   = util_allocStrCpy(className);
			if (firstFree == skirmishAiImpl_size) {
				skirmishAiImpl_size++;
			}
		} else {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Class loading failed for class: %s", className);
		}
	} else {
		success = true;
	}

	if (success) {
		skirmishAIId_skirmishAiImpl[skirmishAIId] = sai;
	}

	return success;
}
Ejemplo n.º 8
0
/**
 * Load the interfaces JVM properties file.
 */
static bool java_readJvmCfgFile(struct Properties* props) {

	bool read = false;

	const size_t props_sizeMax = 256;
	props->size   = 0;
	props->keys   = (const char**) calloc(props_sizeMax, sizeof(char*));
	props->values = (const char**) calloc(props_sizeMax, sizeof(char*));

	// ### read JVM options config file ###
	char* jvmPropFile = callback->DataDirs_allocatePath(interfaceId,
			JVM_PROPERTIES_FILE, false, false, false, false);
	if (jvmPropFile == NULL) {
		// if the version specific file does not exist,
		// try to get the common one
		jvmPropFile = callback->DataDirs_allocatePath(interfaceId,
			JVM_PROPERTIES_FILE, false, false, false, true);
	}

	if (jvmPropFile != NULL) {
		props->size = util_parsePropertiesFile(jvmPropFile,
				props->keys, props->values, props_sizeMax);
		read = true;
		simpleLog_logL(SIMPLELOG_LEVEL_FINE,
				"JVM: arguments loaded from: %s", jvmPropFile);
	} else {
		props->size = 0;
		read = false;
		simpleLog_logL(SIMPLELOG_LEVEL_FINE,
				"JVM: arguments NOT loaded from: %s", jvmPropFile);
	}

	FREE(jvmPropFile);

	return read;
}
Ejemplo n.º 9
0
static jobject java_createAIClassLoader(JNIEnv* env,
		const char* shortName, const char* version) {

#ifdef _WIN32
	static const char* FILE_URL_PREFIX = "file:///";
#else // _WIN32
	static const char* FILE_URL_PREFIX = "file://";
#endif // _WIN32

	jobject o_jClsLoader = NULL;

	static const size_t classPathParts_sizeMax = 512;
	char**              classPathParts = (char**) calloc(classPathParts_sizeMax, sizeof(char*));
	const size_t        classPathParts_size =
			java_createAIClassPath(shortName, version, classPathParts, classPathParts_sizeMax);

	jobjectArray o_cppURLs = jniUtil_createURLArray(env, classPathParts_size);
	if (o_cppURLs == NULL) { return NULL; }
	size_t cpp;
	for (cpp = 0; cpp < classPathParts_size; ++cpp) {
		#ifdef _WIN32
		// we can not use windows path separators in file URLs
		util_strReplaceChar(classPathParts[cpp], '\\', '/');
		#endif

		char* str_fileUrl = util_allocStrCat(2, FILE_URL_PREFIX, classPathParts[cpp]);
		simpleLog_logL(SIMPLELOG_LEVEL_FINE,
				"Skirmish AI %s %s class-path part %i: %s",
				shortName, version, cpp, str_fileUrl);
		jobject jurl_fileUrl = jniUtil_createURLObject(env, str_fileUrl);
		if (jurl_fileUrl == NULL) { return NULL; }
		const bool inserted = jniUtil_insertURLIntoArray(env, o_cppURLs, cpp, jurl_fileUrl);
		if (!inserted) { return NULL; }

		// TODO: check/test if this is allowed/ok
		FREE(str_fileUrl);
		FREE(classPathParts[cpp]);
	}

	o_jClsLoader = jniUtil_createURLClassLoader(env, o_cppURLs);
	if (o_jClsLoader == NULL) { return NULL; }
	o_jClsLoader = jniUtil_makeGlobalRef(env, o_jClsLoader, "Skirmish AI class-loader");

	FREE(classPathParts);

	return o_jClsLoader;
}
Ejemplo n.º 10
0
static bool GetJREPathFromRegistry(char* path, size_t pathSize, const char* arch)
{
	HKEY key, subkey;
	char version[MAXPATHLEN];

	/*
	 * Note: There is a very similar implementation of the following
	 * registry reading code in the Windows java control panel (javacp.cpl).
	 * If there are bugs here, a similar bug probably exists there.  Hence,
	 * changes here require inspection there.
	 */

	// Find the current version of the JRE
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_REG_KEY, 0, KEY_READ, &key) != 0) {
		return false;
	}

	if (!GetStringFromRegistry(key, "CurrentVersion",
			version, sizeof(version))) {
		RegCloseKey(key);
		return false;
	}

	/*if (strcmp(version, wantedVersion) != 0) {
		RegCloseKey(key);
		return false;
	}*/

	// Find directory where the current version is installed.
	if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) {
		RegCloseKey(key);
		return false;
	}

	if (!GetStringFromRegistry(subkey, "JavaHome", path, pathSize)) {
		RegCloseKey(key);
		RegCloseKey(subkey);
		return false;
	}

	RegCloseKey(key);
	RegCloseKey(subkey);

	simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in registry!");
	return true;
}
Ejemplo n.º 11
0
static bool GetJREPathInCommonLocations(char* path, size_t pathSize, const char* arch)
{
	bool found = false;

	static const size_t possLoc_sizeMax = 32;
	char* possLoc[possLoc_sizeMax];
	size_t possLoc_i = 0;

	possLoc[possLoc_i++] = util_allocStrCpy("/usr/local/jdk*");
	possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-sun");
	possLoc[possLoc_i++] = util_allocStrCpy("/usr/lib/jvm/java-?-*");
	possLoc[possLoc_i++] = util_allocStrCpy("~/jdk*");
	possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jdk*");
	possLoc[possLoc_i++] = util_allocStrCpy("~/jre*");
	possLoc[possLoc_i++] = util_allocStrCpy("~/bin/jre*");

	static const size_t globHits_sizeMax = 32;
	char* globHits[globHits_sizeMax];
	size_t l, g;
	for (l=0; l < possLoc_i; ++l) {
		const size_t globHits_size = ExecFileSystemGlob(globHits, globHits_sizeMax, possLoc[l]);
		for (g=0; g < globHits_size; ++g) {
			found = GetJREPathFromBase(path, pathSize, globHits[g], arch);
			if (found) {
				simpleLog_logL(SIMPLELOG_LEVEL_FINER,
						"JRE found common location env var \"%s\"!",
						possLoc[l]);
				goto locSearchEnd;
			}
		}
	}
 locSearchEnd:

	// cleanup
	for (l=0; l < possLoc_i; ++l) {
		free(possLoc[l]);
		possLoc[l] = NULL;
	}

	return found;
}
Ejemplo n.º 12
0
static size_t ExecFileSystemGlob(char** pathHits, size_t pathHits_sizeMax,
		const char* globPattern)
{
	size_t pathHits_size = 0;

	// assemble the command
	static const size_t cmd_sizeMax = 512;
	char cmd[cmd_sizeMax];
	SNPRINTF(cmd, cmd_sizeMax, "find %s/ -maxdepth 0 2> /dev/null", globPattern);

	// execute
	FILE* cmd_fp = popen(cmd, "r");
	if (cmd_fp == NULL) {
		return pathHits_size;
	}

	// parse results
	static const size_t line_sizeMax = 512;
	char line[line_sizeMax];
	while (fgets(line, line_sizeMax, cmd_fp) && (pathHits_size < pathHits_sizeMax)) {
		size_t line_size = strlen(line);
		if (*(line+line_size-1) == '\n') {
			// remove trailing '\n'
			*(line+line_size-1) = '\0';
			line_size--;
		}

		simpleLog_logL(SIMPLELOG_LEVEL_FINEST,
				"glob-hit \"%s\"!", line);

		if (line_size > 0 && *line == '/') {
			*(line+line_size-1) = '\0'; // remove trailing '/'
			pathHits[pathHits_size++] = util_allocStrCpy(line);
		}
	}
	pclose(cmd_fp);

	return pathHits_size;
}
Ejemplo n.º 13
0
static bool java_createJavaVMInitArgs(struct JavaVMInitArgs* vm_args, const struct Properties* jvmProps) {

	// ### evaluate JNI version to use ###
	//jint jniVersion = JNI_VERSION_1_1;
	//jint jniVersion = JNI_VERSION_1_2;
	jint jniVersion = JNI_VERSION_1_4;
	//jint jniVersion = JNI_VERSION_1_6;
	if (jvmProps != NULL) {
		const char* jniVersionFromCfg = java_getValueByKey(jvmProps,
				"jvm.jni.version");
		if (jniVersionFromCfg != NULL) {
			unsigned long int jniVersion_tmp =
					strtoul(jniVersionFromCfg, NULL, 16);
			if (jniVersion_tmp != 0/* && jniVersion_tmp != ULONG_MAX*/) {
				jniVersion = (jint) jniVersion_tmp;
			}
		}
	}
	simpleLog_logL(SIMPLELOG_LEVEL_FINE, "JVM: JNI version: %#x", jniVersion);
	vm_args->version = jniVersion;

	// ### check if debug related JVM options should be used ###
	// if false, the JVM creation will fail if an
	// unknown or invalid option was specified
	bool useDebugOptions = true;
	const char* useDebugOptionsStr = "auto";
	if (jvmProps != NULL) {
		const char* useDebugOptionsFromCfg =
				util_map_getValueByKey(
				jvmProps->size, jvmProps->keys, jvmProps->values,
				"jvm.useDebugOptions");
		if (useDebugOptionsFromCfg != NULL) {
			useDebugOptionsStr = useDebugOptionsFromCfg;
		}
	}
	{
		if (strcmp(useDebugOptionsStr, "auto") == 0
				|| strcmp(useDebugOptionsStr, "Auto") == 0
				|| strcmp(useDebugOptionsStr, "AUTO") == 0
				|| strcmp(useDebugOptionsStr, "a") == 0
				|| strcmp(useDebugOptionsStr, "A") == 0)
		{
			// auto
#if       defined DEBUG
			useDebugOptions = true;
#else  // defined DEBUG
			useDebugOptions = false;
#endif // defined DEBUG
		} else {
			// true or false
			useDebugOptions = util_strToBool(useDebugOptionsStr);
		}
	}

	// ### check if unrecognized JVM options should be ignored ###
	// if false, the JVM creation will fail if an
	// unknown or invalid option was specified
	bool ignoreUnrecognized = true;
	if (jvmProps != NULL) {
		const char* ignoreUnrecognizedFromCfg = java_getValueByKey(jvmProps,
				"jvm.arguments.ignoreUnrecognized");
		if (ignoreUnrecognizedFromCfg != NULL
				&& !util_strToBool(ignoreUnrecognizedFromCfg)) {
			ignoreUnrecognized = false;
		}
	}
	if (ignoreUnrecognized) {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE,
				"JVM: ignoring unrecognized options");
		vm_args->ignoreUnrecognized = JNI_TRUE;
	} else {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE,
				"JVM: NOT ignoring unrecognized options");
		vm_args->ignoreUnrecognized = JNI_FALSE;
	}

	// ### create the Java class-path option ###
	// autogenerate the class path
	static const size_t classPath_sizeMax = 8 * 1024;
	char* classPath = util_allocStr(classPath_sizeMax);
	// ..., autogenerate it ...
	if (!java_createClassPath(classPath, classPath_sizeMax)) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed creating Java class-path.");
		return false;
	}
	if (jvmProps != NULL) {
		// ..., and append the part from the jvm options properties file,
		// if it is specified there
		const char* clsPathFromCfg = java_getValueByKey(jvmProps,
				"jvm.option.java.class.path");
		if (clsPathFromCfg != NULL) {
			STRCATS(classPath, classPath_sizeMax, ENTRY_DELIM);
			STRCATS(classPath, classPath_sizeMax, clsPathFromCfg);
		}
	}
	// create the java.class.path option
	static const size_t classPathOpt_sizeMax = 8 * 1024;
	char* classPathOpt = util_allocStr(classPathOpt_sizeMax);
	STRCPYS(classPathOpt, classPathOpt_sizeMax, "-Djava.class.path=");
	STRCATS(classPathOpt, classPathOpt_sizeMax, classPath);
	FREE(classPath);

	// ### create the Java library-path option ###
	// autogenerate the java library path
	static const size_t libraryPath_sizeMax = 4 * 1024;
	char* libraryPath = util_allocStr(libraryPath_sizeMax);
	// ..., autogenerate it ...
	if (!java_createNativeLibsPath(libraryPath, libraryPath_sizeMax)) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed creating Java library-path.");
		return false;
	}
	if (jvmProps != NULL) {
		// ..., and append the part from the jvm options properties file,
		// if it is specified there
		const char* libPathFromCfg = java_getValueByKey(jvmProps,
				"jvm.option.java.library.path");
		if (libPathFromCfg != NULL) {
			STRCATS(libraryPath, libraryPath_sizeMax, ENTRY_DELIM);
			STRCATS(libraryPath, libraryPath_sizeMax, libPathFromCfg);
		}
	}
	// create the java.library.path option ...
	// autogenerate it, and append the part from the jvm options file,
	// if it is specified there
	static const size_t libraryPathOpt_sizeMax = 4 * 1024;
	char* libraryPathOpt = util_allocStr(libraryPathOpt_sizeMax);
	STRCPYS(libraryPathOpt, libraryPathOpt_sizeMax, "-Djava.library.path=");
	STRCATS(libraryPathOpt, libraryPathOpt_sizeMax, libraryPath);
	FREE(libraryPath);

	// ### create and set all JVM options ###
	static const size_t strOptions_sizeMax = 64;
	const char* strOptions[strOptions_sizeMax];
	size_t op = 0;

	strOptions[op++] = classPathOpt;
	strOptions[op++] = libraryPathOpt;

	static const char* const JCPVAL = "-Djava.class.path=";
	const size_t JCPVAL_size = strlen(JCPVAL);
	static const char* const JLPVAL = "-Djava.library.path=";
	const size_t JLPVAL_size = strlen(JCPVAL);
	if (jvmProps != NULL) {
		// ### add string options from the JVM config file with property name "jvm.option.x" ###
		int i;
		for (i=0; i < jvmProps->size; ++i) {
			if (strcmp(jvmProps->keys[i], "jvm.option.x") == 0 ||
					(useDebugOptions && (strcmp(jvmProps->keys[i], "jvm.option.debug.x") == 0))) {
				const char* const val = jvmProps->values[i];
				const size_t val_size = strlen(val);
				// ignore "-Djava.class.path=..."
				// and "-Djava.library.path=..." options
				if (strncmp(val, JCPVAL, minSize(val_size, JCPVAL_size)) != 0 &&
					strncmp(val, JLPVAL, minSize(val_size, JLPVAL_size)) != 0) {
					strOptions[op++] = val;
				}
			}
		}
	} else {
		// ### ... or set default ones, if the JVM config file was not found ###
		simpleLog_logL(SIMPLELOG_LEVEL_WARNING, "JVM: properties file ("JVM_PROPERTIES_FILE") not found; using default options.");

		strOptions[op++] = "-Xms4M";
		strOptions[op++] = "-Xmx64M";
		strOptions[op++] = "-Xss512K";
		strOptions[op++] = "-Xoss400K";

#if       defined DEBUG
		strOptions[op++] = "-Xcheck:jni";
		strOptions[op++] = "-verbose:jni";
		strOptions[op++] = "-XX:+UnlockDiagnosticVMOptions";
		strOptions[op++] = "-XX:+LogVMOutput";

		strOptions[op++] = "-Xdebug";
		strOptions[op++] = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7777";
		// disable JIT (required for debugging under the classical VM)
		strOptions[op++] = "-Djava.compiler=NONE";
		// disable old JDB
		strOptions[op++] = "-Xnoagent";
#endif // defined DEBUG
	}

	const size_t options_size = op;

	vm_args->options = (struct JavaVMOption*) calloc(options_size, sizeof(struct JavaVMOption));

	// fill strOptions into the JVM options
	simpleLog_logL(SIMPLELOG_LEVEL_FINE, "JVM: options:", options_size);
	char* dd_rw = callback->DataDirs_allocatePath(interfaceId,
			"", true, true, true, false);
	size_t i;
	jint nOptions = 0;
	for (i = 0; i < options_size; ++i) {
		char* tmpOptionString = util_allocStrReplaceStr(strOptions[i],
				"${home-dir}", dd_rw);
		// do not add empty options
		if (tmpOptionString != NULL) {
			if (strlen(tmpOptionString) > 0) {
				vm_args->options[nOptions].optionString = tmpOptionString;
				vm_args->options[nOptions].extraInfo = NULL;
				simpleLog_logL(SIMPLELOG_LEVEL_FINE, "JVM option %ul: %s", nOptions, tmpOptionString);
				nOptions++;
			} else {
				free(tmpOptionString);
				tmpOptionString = NULL;
			}
		}
	}
	vm_args->nOptions = nOptions;

	FREE(dd_rw);
	FREE(classPathOpt);
	FREE(libraryPathOpt);
	simpleLog_logL(SIMPLELOG_LEVEL_FINE, "");

	return true;
}
Ejemplo n.º 14
0
EXPORT(int) initStatic(int _interfaceId,
		const struct SAIInterfaceCallback* _callback) {

	bool success = false;

	// initialize C part of the interface
	interfaceId = _interfaceId;
	callback = _callback;

	const char* const myShortName = callback->AIInterface_Info_getValueByKey(interfaceId,
			AI_INTERFACE_PROPERTY_SHORT_NAME);
	const char* const myVersion = callback->AIInterface_Info_getValueByKey(interfaceId,
			AI_INTERFACE_PROPERTY_VERSION);

	static const int maxProps = 64;
	const char* propKeys[maxProps];
	char* propValues[maxProps];
	int numProps = 0;

	// ### read the interface config file (optional) ###
	static const unsigned int propFilePath_sizeMax = 1024;
	char propFilePath[propFilePath_sizeMax];
	// eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}"
	bool propFileFetched = callback->DataDirs_locatePath(interfaceId,
			propFilePath, propFilePath_sizeMax,
			INTERFACE_PROPERTIES_FILE, false, false, false, false);
	if (!propFileFetched) {
		// if the version specific file does not exist,
		// try to get the common one
		propFileFetched = callback->DataDirs_locatePath(interfaceId,
				propFilePath, propFilePath_sizeMax,
				INTERFACE_PROPERTIES_FILE, false, false, false, true);
	}
	if (propFileFetched) {
		numProps = util_parsePropertiesFile(propFilePath,
				propKeys, (const char**)propValues, maxProps);

		static const unsigned int ddw_sizeMax = 1024;
		char ddw[ddw_sizeMax];
		// eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}"
		bool ddwFetched = callback->DataDirs_locatePath(interfaceId,
				ddw, ddw_sizeMax,
				"", true, true, true, false);
		if (!ddwFetched) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed locating writeable data-dir \"%s\"", ddw);
		}
		int p;
		for (p=0; p < numProps; ++p) {
			char* propValue_tmp = util_allocStrReplaceStr(propValues[p],
					"${home-dir}", ddw);
// 			char* propValue_tmp = util_allocStrReplaceStr(propValues[p],
// 					"${home-dir}/", "");
			free(propValues[p]);
			propValues[p] = propValue_tmp;
		}
	}

	// ### try to fetch the log-level from the properties ###
	int logLevel = SIMPLELOG_LEVEL_NORMAL;
	const char* logLevel_str =
			util_map_getValueByKey(numProps, propKeys, (const char**)propValues,
			"log.level");
	if (logLevel_str != NULL) {
		int logLevel_tmp = atoi(logLevel_str);
		if (logLevel_tmp >= SIMPLELOG_LEVEL_ERROR
				&& logLevel_tmp <= SIMPLELOG_LEVEL_FINEST) {
			logLevel = logLevel_tmp;
		}
	}

	// ### try to fetch whether to use time-stamps from the properties ###
	bool useTimeStamps = true;
	const char* useTimeStamps_str =
			util_map_getValueByKey(numProps, propKeys, (const char**)propValues,
			"log.useTimeStamps");
	if (useTimeStamps_str != NULL) {
		useTimeStamps = util_strToBool(useTimeStamps_str);
	}

	// ### init the log file ###
	char* logFile = util_allocStrCpy(
			util_map_getValueByKey(numProps, propKeys, (const char**)propValues,
			"log.file"));
	if (logFile == NULL) {
		logFile = util_allocStrCatFSPath(2, "log", MY_LOG_FILE);
	}

	static const unsigned int logFilePath_sizeMax = 1024;
	char logFilePath[logFilePath_sizeMax];
	// eg: "~/.spring/AI/Interfaces/Java/${INTERFACE_PROPERTIES_FILE}"
	bool logFileFetched = callback->DataDirs_locatePath(interfaceId,
			logFilePath, logFilePath_sizeMax,
			logFile, true, true, false, false);

	if (logFileFetched) {
		simpleLog_init(logFilePath, useTimeStamps, logLevel, false);
	} else {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed initializing log-file \"%s\"", logFileFetched);
	}

	// log settings loaded from interface config file
	if (propFileFetched) {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "settings loaded from: %s",
				propFilePath);
		int p;
		for (p=0; p < numProps; ++p) {
			simpleLog_logL(SIMPLELOG_LEVEL_FINE, "\t%i: %s = %s",
					p, propKeys[p], propValues[p]);
		}
	} else {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "settings NOT loaded from: %s",
				propFilePath);
	}

	simpleLog_log("This is the log-file of the %s v%s AI Interface",
			myShortName, myVersion);
	simpleLog_log("Using read/write data-directory: %s",
			callback->DataDirs_getWriteableDir(interfaceId));
	simpleLog_log("Using log file: %s", propFilePath);

	FREE(logFile);

	// initialize Java part of the interface
	success = java_initStatic(interfaceId, callback);
	// load the JVM
	success = success && java_preloadJNIEnv();
	if (success) {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "Initialization successfull.");
	} else {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "Initialization failed.");
	}

	return success ? 0 : -1;
}
Ejemplo n.º 15
0
bool java_initStatic(int _interfaceId,
		const struct SAIInterfaceCallback* _callback) {

	interfaceId = _interfaceId;
	callback = _callback;

	// Read the jvm properties config file
	jvmCfgProps = (struct Properties*) malloc(sizeof(struct Properties));
	java_readJvmCfgFile(jvmCfgProps);

	skirmishAIId_sizeMax   = callback->SkirmishAIs_getSize(interfaceId);
	skirmishAiImpl_sizeMax = skirmishAIId_sizeMax;
	skirmishAiImpl_size    = 0;

	skirmishAIId_skirmishAiImpl = (size_t*) calloc(skirmishAIId_sizeMax, sizeof(size_t));
	size_t t;
	for (t = 0; t < skirmishAIId_sizeMax; ++t) {
		skirmishAIId_skirmishAiImpl[t] = 999999;
	}

	skirmishAiImpl_className   = (char**)      calloc(skirmishAiImpl_sizeMax, sizeof(char*));
	skirmishAiImpl_instance    = (jobject*)    calloc(skirmishAiImpl_sizeMax, sizeof(jobject));
	skirmishAiImpl_classLoader = (jobject*)    calloc(skirmishAiImpl_sizeMax, sizeof(jobject));
	size_t sai;
	for (sai = 0; sai < skirmishAiImpl_sizeMax; ++sai) {
		skirmishAiImpl_className[sai]   = NULL;
		skirmishAiImpl_instance[sai]    = NULL;
		skirmishAiImpl_classLoader[sai] = NULL;
	}

	// dynamically load the JVM
	char* jreLocationFile = callback->DataDirs_allocatePath(interfaceId,
			JRE_LOCATION_FILE, false, false, false, false);

	static const size_t jrePath_sizeMax = 1024;
	char jrePath[jrePath_sizeMax];
	bool jreFound = GetJREPath(jrePath, jrePath_sizeMax, jreLocationFile, NULL);
	if (!jreFound) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed locating a JRE installation"
				", you may specify the JAVA_HOME env var.");
		return false;
	}
	FREE(jreLocationFile);

#if defined __arch64__
	static const char* defJvmType = "server";
#else
	static const char* defJvmType = "client";
#endif
	const char* jvmType = java_getValueByKey(jvmCfgProps, "jvm.type");
	if (jvmType == NULL) {
		jvmType = defJvmType;
	}

	static const size_t jvmLibPath_sizeMax = 1024;
	char jvmLibPath[jvmLibPath_sizeMax];
	bool jvmLibFound = GetJVMPath(jrePath, jvmType, jvmLibPath,
			jvmLibPath_sizeMax, NULL);
	if (!jvmLibFound) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed locating the %s version of the JVM, please contact spring devs.", jvmType);
		return false;
	}

	jvmSharedLib = sharedLib_load(jvmLibPath);
	if (!sharedLib_isLoaded(jvmSharedLib)) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed to load the JVM at \"%s\".", jvmLibPath);
		return false;
	} else {
		simpleLog_logL(SIMPLELOG_LEVEL_NORMAL,
				"Successfully loaded the JVM shared library at \"%s\".", jvmLibPath);

		JNI_GetDefaultJavaVMInitArgs_f = (JNI_GetDefaultJavaVMInitArgs_t*)
				sharedLib_findAddress(jvmSharedLib, "JNI_GetDefaultJavaVMInitArgs");
		if (JNI_GetDefaultJavaVMInitArgs_f == NULL) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to load the JVM, function \"%s\" not exported.", "JNI_GetDefaultJavaVMInitArgs");
			return false;
		}

		JNI_CreateJavaVM_f = (JNI_CreateJavaVM_t*)
				sharedLib_findAddress(jvmSharedLib, "JNI_CreateJavaVM");
		if (JNI_CreateJavaVM_f == NULL) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to load the JVM, function \"%s\" not exported.", "JNI_CreateJavaVM");
			return false;
		}

		JNI_GetCreatedJavaVMs_f = (JNI_GetCreatedJavaVMs_t*)
				sharedLib_findAddress(jvmSharedLib, "JNI_GetCreatedJavaVMs");
		if (JNI_GetCreatedJavaVMs_f == NULL) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to load the JVM, function \"%s\" not exported.", "JNI_GetCreatedJavaVMs");
			return false;
		}
	}

	java_establishJavaEnv();
	JNIEnv* env = java_getJNIEnv();
	bool success = (env != NULL);
	if (success) {
		const int res = eventsJniBridge_initStatic(env, skirmishAIId_sizeMax);
		success = (res == 0);
	}
	java_establishSpringEnv();

	return success;
}
Ejemplo n.º 16
0
//#define LOC_PROP_FILE
bool GetJREPathFromConfig(char* path, size_t pathSize, const char* configFile)
{
#if defined LOC_PROP_FILE
	// assume the config file is in properties file format
	// and that the property JRE_PATH_PROPERTY contains
	// the absolute path to the JRE to use
	static const size_t props_sizeMax = 64;

	const char* props_keys[props_sizeMax];
	const char* props_values[props_sizeMax];

	const size_t props_size = util_parsePropertiesFile(configFile, props_keys,
			props_values, props_sizeMax);

	const char* jvmLocation = util_map_getValueByKey(
			props_size, props_keys, props_values,
			JRE_PATH_PROPERTY);

	if (jvmLocation == NULL) {
		simpleLog_logL(LOG_LEVEL_DEBUG, "JRE not found in config file!");
		return false;
	} else {
		simpleLog_logL(LOG_LEVEL_NOTICE, "JRE found in config file!");
		STRCPY_T(path, pathSize, jvmLocation);
		return true;
	}
#else // defined LOC_PROP_FILE
	// assume the config file is a plain text file containing nothing but
	// the absolute path to the JRE to use in the first line

	bool found = false;

	FILE* cfp = fopen(configFile, "r");
	if (cfp == NULL) {
		return found;
	}

	// parse results
	static const size_t line_sizeMax = 1024;
	char line[line_sizeMax];
	if (fgets(line, line_sizeMax, cfp)) {
		size_t line_size = strlen(line);
		if (*(line+line_size-1) == '\n') {
			// remove trailing '\n'
			*(line+line_size-1) = '\0';
			line_size--;
		}

		simpleLog_logL(LOG_LEVEL_NOTICE,
				"Fetched JRE location from \"%s\"!", configFile);

		if (line_size > 0 && *line == '/') {
			*(line+line_size-1) = '\0'; // remove trailing '/'
		}
		STRCPY_T(path, pathSize, line);
		found = true;
	}
	fclose(cfp);

	return found;
#endif // defined LOC_PROP_FILE
}
Ejemplo n.º 17
0
static JNIEnv* java_getJNIEnv() {

	JNIEnv* ret = NULL;

	if (g_jvm == NULL) {
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "Creating the JVM.");

		JNIEnv* env = NULL;
		JavaVM* jvm = NULL;
		struct JavaVMInitArgs vm_args;
		jint res = 0;

		if (!java_createJavaVMInitArgs(&vm_args, jvmCfgProps)) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed initializing JVM init-arguments.");
			goto end;
		}

		// Looking for existing JVMs might be problematic,
		// cause they could be initialized with other
		// JVM-arguments then we need.
		// But as we can not use DestroyJavaVM, cause it makes
		// creating a new one for hte same process impossible
		// (a (SUN?) JVM limitation), we have to do it this way,
		// to support /aireload and /aicontrol for Java Skirmish AIs.
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "looking for existing JVMs ...");
		jsize numJVMsFound = 0;

		// jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs);
		// Returns all Java VMs that have been created.
		// Pointers to VMs are written in the buffer vmBuf,
		// in the order they were created.
		static const int maxVmsToFind = 1;
		res = JNI_GetCreatedJavaVMs_f(&jvm, maxVmsToFind, &numJVMsFound);
		if (res != 0) {
			jvm = NULL;
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed fetching list of running JVMs: %i - %s",
					res, jniUtil_getJniRetValDescription(res));
			goto end;
		}
		simpleLog_logL(SIMPLELOG_LEVEL_FINE, "number of existing JVMs: %i", numJVMsFound);

		if (numJVMsFound > 0) {
			simpleLog_logL(SIMPLELOG_LEVEL_FINE, "using an already running JVM.");
		} else {
			simpleLog_logL(SIMPLELOG_LEVEL_FINE, "creating JVM...");
			res = JNI_CreateJavaVM_f(&jvm, (void**) &env, &vm_args);
			if (res != 0 || (*env)->ExceptionCheck(env)) {
				simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
						"Failed to create Java VM: %i - %s",
						res, jniUtil_getJniRetValDescription(res));
				goto end;
			}
		}

		// free the JavaVMInitArgs content
		jint i;
		for (i = 0; i < vm_args.nOptions; ++i) {
			FREE(vm_args.options[i].optionString);
		}
		FREE(vm_args.options);

		//res = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void**) &env, NULL);
		res = (*jvm)->AttachCurrentThread(jvm, (void**) &env, NULL);
		if (res < 0 || (*env)->ExceptionCheck(env)) {
			if ((*env)->ExceptionCheck(env)) {
				(*env)->ExceptionDescribe(env);
			}
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
					"Failed to attach JVM to current thread: %i - %s",
					res, jniUtil_getJniRetValDescription(res));
			goto end;
		}

end:
		if (env == NULL || jvm == NULL || (*env)->ExceptionCheck(env)
				|| res != 0) {
			simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "JVM: Failed creating.");
			if (env != NULL && (*env)->ExceptionCheck(env)) {
				(*env)->ExceptionDescribe(env);
			}
			if (jvm != NULL) {
				// Never destroy the JVM, because it can not be created again
				// for the same thread; would allways fail with return value -1
				//res = (*jvm)->DestroyJavaVM(jvm);
			}
			g_jvm = NULL;
			ret = NULL;
		} else {
			g_jvm = jvm;
			ret = env;
		}
	} else {
		ret = java_reattachCurrentThread();
	}

	return ret;
}
Ejemplo n.º 18
0
static bool java_loadSkirmishAI(JNIEnv* env,
		const char* shortName, const char* version, const char* className,
		jobject* o_ai, jobject* o_aiClassLoader) {

/*	// convert className from "com.myai.AI" to "com/myai/AI"
	const size_t classNameP_sizeMax = strlen(className) + 1;
	char classNameP[classNameP_sizeMax];
	STRCPYS(classNameP, classNameP_sizeMax, className);
	util_strReplaceChar(classNameP, '.', '/');*/

	// get the AIs private class-loader
	jobject o_global_aiClassLoader =
			java_createAIClassLoader(env, shortName, version);
	if (o_global_aiClassLoader == NULL) { return false; }
	*o_aiClassLoader = o_global_aiClassLoader;

	// get the AI interface (from AIInterface.jar)
	if (g_cls_ai_int == NULL) {
		g_cls_ai_int = jniUtil_findClass(env, INT_AI);
		if (g_cls_ai_int == NULL) { return false; }
		g_cls_ai_int = jniUtil_makeGlobalRef(env, g_cls_ai_int, "AI interface class");
		if (g_cls_ai_int == NULL) { return false; }
	}

	// get the AI implementation class (from SkirmishAI.jar)
	jclass cls_ai = jniUtil_findClassThroughLoader(env, o_global_aiClassLoader,
			className);
	if (cls_ai == NULL) { return false; }

	const bool implementsAIInt = (bool) (*env)->IsAssignableFrom(env, cls_ai, g_cls_ai_int);
	bool hasException = (*env)->ExceptionCheck(env);
	if (!implementsAIInt || hasException) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"AI class not assignable from interface "INT_AI": %s", className);
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "possible reasons (this list could be incomplete):");
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "* "INT_AI" interface not implemented");
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR, "* The AI is not compiled for the Java AI Interface version in use");
		if (hasException) {
			(*env)->ExceptionDescribe(env);
		}
		return false;
	}

	// get factory no-arg ctor
	jmethodID m_ai_ctor = jniUtil_getMethodID(env, cls_ai, "<init>", "()V");
	if (m_ai_ctor == NULL) { return false; }

	// get AI instance
	jobject o_local_ai = (*env)->NewObject(env, cls_ai, m_ai_ctor);
	hasException = (*env)->ExceptionCheck(env);
	if (!o_local_ai || hasException) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Failed fetching AI instance for class: %s", className);
		if (hasException) {
			(*env)->ExceptionDescribe(env);
		}
		return false;
	}

	// make the AI a global reference,
	// so it will not be garbage collected,
	// even after this method returned
	*o_ai = jniUtil_makeGlobalRef(env, o_local_ai, "AI instance");

	return true;
}
Ejemplo n.º 19
0
/**
 * Creates the AI Interface global Java class path.
 *
 * It will consist of the following:
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/AIInterface.jar
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?config/[*].jar
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?resources/[*].jar
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/(j)?script/[*].jar
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/
 * {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/{version}/jlib/[*].jar
 * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/
 * TODO: {spring-data-dir}/{AI_INTERFACES_DATA_DIR}/Java/common/jlib/[*].jar
 */
static size_t java_createClassPath(char* classPathStr, const size_t classPathStr_sizeMax) {

	// the dirs and .jar files in the following array
	// will be concatenated with intermediate path separators
	// to form the classPathStr
	static const size_t classPath_sizeMax = 128;
	char**              classPath = (char**) calloc(classPath_sizeMax, sizeof(char*));
	size_t              classPath_size = 0;

	// the Java AI Interfaces java library file path (.../AIInterface.jar)
	// We need to search for this jar, instead of looking only where
	// the AIInterface.so/InterfaceInfo.lua is, because on some systems
	// (eg. Debian), the .so is in /usr/lib, and the .jar's  are in /usr/shared.
	char* mainJarPath = callback->DataDirs_allocatePath(interfaceId,
			JAVA_AI_INTERFACE_LIBRARY_FILE_NAME,
			false, false, false, false);
	classPath[classPath_size++] = util_allocStrCpy(mainJarPath);

	bool ok = util_getParentDir(mainJarPath);
	if (!ok) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Retrieving the parent dir of the path to AIInterface.jar (%s) failed.",
				mainJarPath);
	}
	char* jarsDataDir = mainJarPath;
	mainJarPath = NULL;

	// the directories in the following list will be searched for .jar files
	// which will then be added to the classPathStr, plus the dirs will be added
	// to the classPathStr directly, so you can keep .class files in there
	static const size_t jarDirs_sizeMax = 128;
	char**              jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*));
	size_t              jarDirs_size = 0;

	// add to classpath:
	// {spring-data-dir}/Interfaces/Java/0.1/${x}/
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jconfig");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "config");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jresources");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "resources");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jscript");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "script");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, jarsDataDir, "jlib");
	// "lib" is for native libs only

	// add the jar dirs (for .class files) and all contained .jars recursively
	size_t jd, jf;
	for (jd=0; (jd < jarDirs_size) && (classPath_size < classPath_sizeMax); ++jd) {
		if (util_fileExists(jarDirs[jd])) {
			// add the dir directly
			// For this to work properly with URLClassPathHandler,
			// we have to ensure there is a '/' at the end,
			// for the class-path-part to be recognized as a directory.
			classPath[classPath_size++] = util_allocStrCat(2, jarDirs[jd], "/");

			// add the contained jars recursively
			static const size_t jarFiles_sizeMax = 128;
			char**              jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*));
			const size_t        jarFiles_size = util_listFiles(jarDirs[jd], ".jar",
					jarFiles, true, jarFiles_sizeMax);
			for (jf=0; (jf < jarFiles_size) && (classPath_size < classPath_sizeMax); ++jf) {
				classPath[classPath_size++] = util_allocStrCatFSPath(2,
						jarDirs[jd], jarFiles[jf]);
				FREE(jarFiles[jf]);
			}
			FREE(jarFiles);
		}
		FREE(jarDirs[jd]);
	}
	FREE(jarDirs);

	// concat the classpath entries
	classPathStr[0] = '\0';
	if (classPath[0] != NULL) {
		STRCATS(classPathStr, classPathStr_sizeMax, classPath[0]);
		FREE(classPath[0]);
	}
	size_t cp;
	for (cp=1; cp < classPath_size; ++cp) {
		if (classPath[cp] != NULL) {
			STRCATS(classPathStr, classPathStr_sizeMax, ENTRY_DELIM);
			STRCATS(classPathStr, classPathStr_sizeMax, classPath[cp]);
			FREE(classPath[cp]);
		}
	}
	FREE(classPath);

	return classPath_size;
}
Ejemplo n.º 20
0
/**
 * Creates a Skirmish AI local Java class path.
 *
 * It will consist of the following:
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?config/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?resources/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/(j)?script/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/jlib/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?config/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?resources/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/(j)?script/[*].jar
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/
 * {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/common/jlib/[*].jar
 */
static size_t java_createAIClassPath(const char* shortName, const char* version,
		char** classPathParts, const size_t classPathParts_sizeMax) {

	size_t classPathParts_size = 0;

	// the .jar files in the following list will be added to the classpath
	const size_t jarFiles_sizeMax = classPathParts_sizeMax;
	char**       jarFiles = (char**) calloc(jarFiles_sizeMax, sizeof(char*));
	size_t       jarFiles_size = 0;

	const char* const skirmDD =
			callback->SkirmishAIs_Info_getValueByKey(interfaceId,
			shortName, version,
			SKIRMISH_AI_PROPERTY_DATA_DIR);
	if (skirmDD == NULL) {
		simpleLog_logL(SIMPLELOG_LEVEL_ERROR,
				"Retrieving the data-dir of Skirmish AI %s-%s failed.",
				shortName, version);
	}
	// {spring-data-dir}/{SKIRMISH_AI_DATA_DIR}/{ai-name}/{ai-version}/SkirmishAI.jar
	jarFiles[jarFiles_size++] = util_allocStrCatFSPath(2,
			skirmDD, "SkirmishAI.jar");

	// the directories in the following list will be searched for .jar files
	// which then will be added to the classpath, plus they will be added
	// to the classpath directly, so you can keep .class files in there
	const size_t jarDirs_sizeMax = classPathParts_sizeMax;
	char**       jarDirs = (char**) calloc(jarDirs_sizeMax, sizeof(char*));
	size_t       jarDirs_size = 0;

	// add to classpath ...

	// {spring-data-dir}/Skirmish/MyJavaAI/0.1/SkirmishAI/
	// this can be usefull for AI devs while testing,
	// if they do not want to put everything into a jar all the time
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "SkirmishAI");

	// add to classpath:
	// {spring-data-dir}/Skirmish/MyJavaAI/0.1/${x}/
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jconfig");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "config");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jresources");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "resources");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jscript");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "script");
	jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDD, "jlib");
	// "lib" is for native libs only

	// add the dir common for all versions of the Skirmish AI,
	// if it is specified and exists
	const char* const skirmDDCommon =
			callback->SkirmishAIs_Info_getValueByKey(interfaceId,
			shortName, version,
			SKIRMISH_AI_PROPERTY_DATA_DIR_COMMON);
	if (skirmDDCommon != NULL) {
		// add to classpath:
		// {spring-data-dir}/Skirmish/MyJavaAI/common/${x}/
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jconfig");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "config");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jresources");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "resources");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jscript");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "script");
		jarDirs[jarDirs_size++] = util_allocStrCatFSPath(2, skirmDDCommon, "jlib");
		// "lib" is for native libs only
	}

	// add the directly specified .jar files
	size_t jf;
	for (jf = 0; (jf < jarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++jf) {
		classPathParts[classPathParts_size++] = util_allocStrCpy(jarFiles[jf]);
		FREE(jarFiles[jf]);
	}

	// add the dirs and the contained .jar files
	size_t jd, sjf;
	for (jd = 0; (jd < jarDirs_size) && (classPathParts_size < classPathParts_sizeMax); ++jd)
	{
		if (jarDirs[jd] != NULL && util_fileExists(jarDirs[jd])) {
			// add the jar dir (for .class files)
			// For this to work properly with URLClassPathHandler,
			// we have to ensure there is a '/' at the end,
			// for the class-path-part to be recognized as a directory.
			classPathParts[classPathParts_size++] = util_allocStrCat(2, jarDirs[jd], "/");

			// add the jars in the dir
			const size_t subJarFiles_sizeMax = classPathParts_sizeMax - classPathParts_size;
			char**       subJarFiles = (char**) calloc(subJarFiles_sizeMax, sizeof(char*));
			const size_t subJarFiles_size = util_listFiles(jarDirs[jd], ".jar",
					subJarFiles, true, subJarFiles_sizeMax);
			for (sjf = 0; (sjf < subJarFiles_size) && (classPathParts_size < classPathParts_sizeMax); ++sjf) {
				// .../[*].jar
				classPathParts[classPathParts_size++] =
						util_allocStrCatFSPath(2, jarDirs[jd], subJarFiles[sjf]);
				FREE(subJarFiles[sjf]);
			}
			FREE(subJarFiles);
		}
		FREE(jarDirs[jd]);
	}

	FREE(jarDirs);
	FREE(jarFiles);

	return classPathParts_size;
}