All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gridvise.logical.Launchable.scala Maven / Gradle / Ivy

The newest version!
package org.gridvise.logical

import java.lang.Boolean
import java.lang.String
import java.util.Date
import scala.collection.mutable.HashMap
import scala.collection.mutable.HashSet
import scala.sys.process.ProcessIO
import scala.sys.process.stringToProcess
import org.gridvise.logical.logbroker.LogBroker
import org.gridvise.logical.os.MachineInfo
import org.gridvise.logical.os.OSOperations
import org.gridvise.mgmtcache.coh.entity.launchable.LaunchableCache
import org.gridvise.mgmtcache.coh.entity.launchable.LaunchableKey
import org.gridvise.mgmtcache.coh.entity.threaddumps.ThreadDumpCache
import org.gridvise.mgmtcache.coh.entity.threaddumps.ThreadDumpKey
import org.gridvise.util.AsyncInvoker
import org.gridvise.util.Dictionary
import org.gridvise.xmlbindings.DictionaryEntryable
import org.slf4j.LoggerFactory

class Launchable(var launchableKey: LaunchableKey, ordinal: Integer) extends Serializable {

  def logger = LoggerFactory.getLogger(this.getClass())
  final var NOT_RUNNING = "not started"
  final var STARTING = "starting"

  final val COUNTER_VAR_PACEHOLDER = "\\$\\{GV_COUNTER\\}"
  final val JVM_NAME_VAR_PACEHOLDER = "\\$\\{GV_JVM_NAME\\}"

  var jvmOptions = new HashMap[String, String]()
  var classPathEntries = new HashSet[String]()
  var mainClass: String = _
  var jvmArgs: String = _
  var machineName = MachineInfo.getMachineName()
  var configName: String = _
  var nodeGroupName: String = _
  var running: Boolean = false
  var delay = -1

  var gridProperties = new HashMap[String, String]()

  def this(clusterId: Long, ordinal: Integer) = this(new LaunchableKey(MachineInfo.getMachineName(), clusterId), ordinal)

  var processIdentifier = configName + " " + ordinal


  //  def act() {
  //    while (true) {
  //      receive {
  //        case Start => startjvm()
  //      }
  //    }
  //  }

  //  def go() {
  //    this.start()
  //    this ! start
  //  }

  def start() {
    val command = buildCommand()
    if (running) {
      logger.info("Already running %s".format(command))
    } else {
      AsyncInvoker.async {
        processIdentifier = configName + " " + ordinal + STARTING
        LaunchableCache.putLaunchable(this)
        logger.info(command)
        if (delay != -1) {
          //already setting status to started so that gui shows node as green //TODO revisit
          running = true
          LaunchableCache.putLaunchable(this)
          logger.info("Will start delayed by %s millis".format(delay))
          Thread.sleep(delay)
        }
        logger.info("Starting now %s".format(command))
        val pio = new ProcessIO(_ => (),
          stdout => scala.io.Source.fromInputStream(stdout)
            .getLines.foreach(l => LogBroker.handleInfoLine(getLaunchableKey(), l)),
          stderr => scala.io.Source.fromInputStream(stderr)
            .getLines.foreach(l => LogBroker.handleErrorLine(getLaunchableKey(), l)))
        var p = command.run(pio)
        //var p = command.run()
        processIdentifier = configName + " " + ordinal + " (pid="+OSOperations.getProcessIdentifier(p) +")"
        running = true
        LaunchableCache.putLaunchable(this)
        subscribeCallback(Dictionary.gridDictionary().MemberId)
        subscribeCallback(Dictionary.gridDictionary().Role)
        //subscribeLogBasedClusterEvent()

      }
    }
  }

  def subscribeLogBasedClusterEvent() {
    Dictionary.gridDictionary().productIterator.foreach(
      a => LogBroker.subscribeEventStream(launchableKey, a.asInstanceOf[DictionaryEntryable]))
  }

  def subscribeCallback(de: DictionaryEntryable) {
    val callback = (x: String) => LaunchableCache.setGridProperty(this.getLaunchableKey(), de, x)
    LogBroker.subscribeCallback(this.getLaunchableKey(), de, callback)
  }

  def stop() {
    OSOperations.stopProcess(this.processIdentifier)
    notRunning()
  }

  def notRunning() {
    running = false
    processIdentifier = configName + " " + ordinal
    persistState()
  }

  def persistState() {
    LaunchableCache.putLaunchable(this)
  }

  def threadDump(): ThreadDump = {
    threadDump(new Date())
  }

  def threadDump(triggerDate: Date): ThreadDump = {
    if (isRunning) {
      var logSubscriber = LogBroker.subscribe(getLaunchableKey(), Dictionary.jvmDictionary().EndOfStacktrace);

      OSOperations.threadDump(this.processIdentifier)
      while (!logSubscriber.isComplete) {
        logger.info("Waiting for log subscriber to complete")
        logSubscriber.synchronized {
          //FIXME what's this??
          logSubscriber.wait(1000)
          if (logSubscriber.out.length() == 0) {
            logSubscriber.isComplete = true
          }
        }
      }
      asyncCacheThreadDump(triggerDate, logSubscriber.out)
      //      logSubscriber.out
    } else {
      //      NOT_RUNNING
      new ThreadDump(NOT_RUNNING, machineName, nodeGroupName, configName)
    }
  }

  //TODO make async
  def asyncCacheThreadDump(triggerDate: Date, dump: String): ThreadDump = {
    var threadDumpKey = new ThreadDumpKey(this.getLaunchableKey(), triggerDate)
    var td = new ThreadDump(dump, machineName, nodeGroupName, configName)
    ThreadDumpCache.put(threadDumpKey, new ThreadDump(dump, machineName, nodeGroupName, configName))
    td
  }

  def isRunning(): Boolean = running

  def getLaunchableKey() = {
    this.launchableKey
  }

  def getClusterId() = this.launchableKey.clusterId

  def buildCommand(): String = {
    //java -classpath C:\java\MyClasses;C:\java\OtherClasses ...
    var command = OSOperations.getJavaCommand()

    command += appendJVMOptions(command)
    command += appendClasspathEntries(command)

    command += " " + mainClass
    if ("null" != jvmArgs + "") command += " " + jvmArgs

    command
  }

  def appendClasspathEntries(command: String): String = {
    //java -classpath C:\java\MyClasses;C:\java\OtherClasses ...
    var cpFragment = " -classpath "
    classPathEntries.foreach { cpe =>
      cpFragment += (cpe + OSOperations.getClasspathSeparator())
    }
    removeLastCharacter(cpFragment)
  }

  def removeLastCharacter(in: String): String = {
    in.substring(0, in.length() - 1)
  }

  def appendJVMOptions(command: String): String = {
    var optionFragment = ""
    jvmOptions.foreach {
      case (key, value) => {
        var v = value.replaceAll(COUNTER_VAR_PACEHOLDER, this.ordinal.toString())
        v = v.replaceAll(JVM_NAME_VAR_PACEHOLDER, this.configName)
        optionFragment += " " + key + v
      }
    }
    optionFragment
  }

  def addGridProperty(dictionaryEntry: DictionaryEntryable, value: String) {
    this.gridProperties.put(dictionaryEntry.getClass().getSimpleName(), value);
  }

  def getGridProperty(dictionaryEntry: DictionaryEntryable): String = {
    this.gridProperties.get(dictionaryEntry.getClass().getSimpleName()).get;
  }

  override def toString() = "[machineName=" + machineName + ", pid=" + this.processIdentifier + ", configName=" + this.configName + ", nodeGroupName=" + this.nodeGroupName + ", clusterId=" + this.getClusterId() + ", mainClass=" + this.mainClass + ", gridProperties=" + this.gridProperties + "]\n" + this.buildCommand() + "\n\n"
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy