diff --git a/launcher/src/main/kotlin/net/corda/launcher/Launcher.kt b/launcher/src/main/kotlin/net/corda/launcher/Launcher.kt index 18d704f60e..9ef98a40e6 100644 --- a/launcher/src/main/kotlin/net/corda/launcher/Launcher.kt +++ b/launcher/src/main/kotlin/net/corda/launcher/Launcher.kt @@ -8,6 +8,41 @@ import kotlin.system.exitProcess fun main(args: Array) { + if(args.isEmpty()) { + println("Usage: launcher [args]") + exitProcess(0) + } + + // TODO: --base-directory is specific of the Node app, it should be controllable by a config property + val nodeBaseDir = Settings.WORKING_DIR + .resolve(getBaseDirectory(args) ?: ".") + .toAbsolutePath() + + val appClassLoader = setupClassLoader(nodeBaseDir) + + val appMain = try { + appClassLoader + .loadClass(args[0]) + .getMethod("main", Array::class.java) + } catch (e: Exception) { + System.err.println("Error looking for method 'main' in class ${args[0]}:") + e.printStackTrace() + exitProcess(1) + } + + // Propagate current working directory via system property, to patch it after javapackager + System.setProperty("corda.launcher.cwd", nodeBaseDir.toString()) + System.setProperty("user.dir", nodeBaseDir.toString()) + + try { + appMain.invoke(null, args.sliceArray(1..args.lastIndex)) + } catch (e: Exception) { + e.printStackTrace() + exitProcess(1) + } +} + +private fun setupClassLoader(nodeBaseDir: Path): ClassLoader { val sysClassLoader = ClassLoader.getSystemClassLoader() val appClassLoader = (sysClassLoader as? Loader) ?: { @@ -15,16 +50,7 @@ fun main(args: Array) { Loader(sysClassLoader) } () - if(args.isEmpty()) { - println("Usage: launcher ") - exitProcess(0) - } - - // Resolve plugins directory and extend classpath - val nodeBaseDir = Settings.WORKING_DIR - .resolve(getBaseDirectory(args) ?: ".") - .toAbsolutePath() - + // Lookup plugins and extend classpath val pluginURLs = Settings.PLUGINS.flatMap { val entry = nodeBaseDir.resolve(it) if (Files.isDirectory(entry)) { @@ -36,19 +62,10 @@ fun main(args: Array) { appClassLoader.augmentClasspath(pluginURLs) - // Propagate current working directory via system property, to patch it after javapackager - System.setProperty("corda.launcher.cwd", nodeBaseDir.toString()) - System.setProperty("user.dir", nodeBaseDir.toString()) + // For logging + System.setProperty("corda.launcher.appclassloader.urls", appClassLoader.urLs.joinToString(":")) - try { - appClassLoader - .loadClass(args[0]) - .getMethod("main", Array::class.java) - .invoke(null, args.sliceArray(1..args.lastIndex)) - } catch (e: Exception) { - e.printStackTrace() - exitProcess(1) - } + return appClassLoader } private fun getBaseDirectory(args: Array): String? { diff --git a/launcher/src/main/kotlin/net/corda/launcher/Settings.kt b/launcher/src/main/kotlin/net/corda/launcher/Settings.kt index bad9794b6b..11aa7ca87a 100644 --- a/launcher/src/main/kotlin/net/corda/launcher/Settings.kt +++ b/launcher/src/main/kotlin/net/corda/launcher/Settings.kt @@ -8,19 +8,30 @@ import java.nio.file.Paths import java.util.* import kotlin.collections.HashSet +// Expose Corda bootstrapping settings from property file object Settings { - val CORDA_RUNTIME_SETTINGS = "../runtime.properties" - val WORKING_DIR: Path + // JavaPackager reset cwd to the "/apps" subfolder, so its location is in the parent directory + private val LAUNCHER_PATH = Paths.get("..") + + // Launcher property file + private val CORDA_RUNTIME_SETTINGS = LAUNCHER_PATH.resolve("runtime.properties") + + // The application working directory + val WORKING_DIR: Path = System.getenv("CORDA_LAUNCHER_CWD")?.let {Paths.get(it)} ?: LAUNCHER_PATH + + // Application classpath val CLASSPATH: List + + // Plugin directories (all contained jar files are added to classpath) val PLUGINS: List - val LIBPATH: Path + + // Path of the "lib" subdirectory in bundle + private val LIBPATH: Path init { - WORKING_DIR = Paths.get(System.getenv("CORDA_LAUNCHER_CWD") ?: "..") - val settings = Properties().apply { - load(FileInputStream(CORDA_RUNTIME_SETTINGS)) + load(FileInputStream(CORDA_RUNTIME_SETTINGS.toFile())) } LIBPATH = Paths.get(settings.getProperty("libpath") ?: ".") @@ -29,7 +40,7 @@ object Settings { } private fun parseClasspath(config: Properties): List { - val libDir = Paths.get("..").resolve(LIBPATH).toAbsolutePath() + val libDir = LAUNCHER_PATH.resolve(LIBPATH).toAbsolutePath() val cp = config.getProperty("classpath") ?: throw Error("Missing 'classpath' property from config")