blob: defd86e8cfc079492e3794b87ef02b63bb8f5042 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.gearpump.cluster.main
import java.io.File
import java.net.{URL, URLClassLoader}
import java.util.jar.JarFile
import org.apache.gearpump.cluster.client.RuntimeEnvironment
import org.apache.gearpump.util.{Constants, LogUtil, MasterClientCommand, Util}
import scala.util.{Failure, Success, Try}
/** Tool to submit an application jar to cluster */
object AppSubmitter extends MasterClientCommand with ArgumentsParser {
override val ignoreUnknownArgument = true
override val description = "Submit an application to Master by providing a jar"
override val options: Array[(String, CLIOption[Any])] = Array(
"namePrefix" -> CLIOption[String]("<application name prefix>", required = false,
defaultValue = Some("")),
"jar" -> CLIOption("<application>.jar", required = true),
"executors" -> CLIOption[Int]("number of executor to launch", required = false,
defaultValue = None),
"verbose" -> CLIOption("<print verbose log on console>", required = false,
defaultValue = Some(false)),
// For document purpose only, OPTION_CONFIG option is not used here.
// OPTION_CONFIG is parsed by parent shell command "Gear" transparently.
Gear.OPTION_CONFIG -> CLIOption("custom configuration file", required = false,
defaultValue = None))
def main(akkaConf: Config, args: Array[String]): Unit = {
val config = parse(args)
if (null != config) {
val verbose = config.getBoolean("verbose")
if (verbose) {
LogUtil.verboseLogToConsole()
}
val jar = config.getString("jar")
// Set jar path to be submitted to cluster
System.setProperty(Constants.GEARPUMP_APP_JAR, jar)
if (config.exists("executors")) {
System.setProperty(Constants.APPLICATION_EXECUTOR_NUMBER,
config.getInt("executors").toString)
}
val namePrefix = config.getString("namePrefix")
if (namePrefix.nonEmpty) {
if (!Util.validApplicationName(namePrefix)) {
throw new Exception(s"$namePrefix is not a valid prefix for an application name")
}
System.setProperty(Constants.GEARPUMP_APP_NAME_PREFIX, namePrefix)
}
val jarFile = new java.io.File(jar)
// Start main class
if (!jarFile.exists()) {
throw new Exception(s"jar $jar does not exist")
}
val classLoader: URLClassLoader = new URLClassLoader(Array(new URL("file:" +
jarFile.getAbsolutePath)), Thread.currentThread().getContextClassLoader)
val (main, arguments) = parseMain(jarFile, config.remainArgs, classLoader)
// Set to context classLoader. ActorSystem pick context classLoader in preference
Thread.currentThread().setContextClassLoader(classLoader)
val clazz = classLoader.loadClass(main)
val mainMethod = clazz.getMethod("main", classOf[Array[String]])
mainMethod.invoke(null, arguments)
}
}
private def parseMain(jar: File, remainArgs: Array[String],
classLoader: ClassLoader): (String, Array[String]) = {
if (remainArgs.nonEmpty && Try(classLoader.loadClass(remainArgs.head)).isSuccess) {
(remainArgs.head, remainArgs.tail)
} else {
val mainInManifest =
new JarFile(jar).getManifest.getMainAttributes.getValue("Main-Class")
val args = remainArgs.mkString(" ")
Try(classLoader.loadClass(mainInManifest)) match {
case Success(_) =>
// scalastyle:off println
Console.println(
s"""Can't load main class in arguments $args
|Loading $mainInManifest in manifest""".stripMargin)
// scalastyle:on println
(mainInManifest, remainArgs)
case Failure(_) =>
throw new IllegalArgumentException(
s"Can't load main class in arguments $args or $mainInManifest in manifest")
}
}
}
}