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

pl.touk.nussknacker.engine.compile.ProcessCompilerData.scala Maven / Gradle / Ivy

The newest version!
package pl.touk.nussknacker.engine.compile

import cats.data.ValidatedNel
import pl.touk.nussknacker.engine.api.component.ComponentType
import pl.touk.nussknacker.engine.api.context.ProcessCompilationError
import pl.touk.nussknacker.engine.api.dict.EngineDictRegistry
import pl.touk.nussknacker.engine.api.process.ComponentUseCase
import pl.touk.nussknacker.engine.api.{JobData, Lifecycle, ProcessListener}
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess
import pl.touk.nussknacker.engine.compile.nodecompilation.{LazyParameterCreationStrategy, NodeCompiler}
import pl.touk.nussknacker.engine.compiledgraph.CompiledProcessParts
import pl.touk.nussknacker.engine.definition.fragment.FragmentParametersDefinitionExtractor
import pl.touk.nussknacker.engine.definition.model.ModelDefinitionWithClasses
import pl.touk.nussknacker.engine.expression.ExpressionEvaluator
import pl.touk.nussknacker.engine.graph.node.{NodeData, WithComponent}
import pl.touk.nussknacker.engine.resultcollector.ResultCollector
import pl.touk.nussknacker.engine.util.Implicits.RichScalaMap
import pl.touk.nussknacker.engine.variables.GlobalVariablesPreparer
import pl.touk.nussknacker.engine.{CustomProcessValidator, Interpreter}

/*
  This is helper class, which collects pieces needed for various stages of compilation process

 */
object ProcessCompilerData {

  def prepare(
      jobData: JobData,
      definitionWithTypes: ModelDefinitionWithClasses,
      dictRegistry: EngineDictRegistry,
      listeners: Seq[ProcessListener],
      userCodeClassLoader: ClassLoader,
      resultsCollector: ResultCollector,
      componentUseCase: ComponentUseCase,
      customProcessValidator: CustomProcessValidator,
      nonServicesLazyParamStrategy: LazyParameterCreationStrategy = LazyParameterCreationStrategy.default
  ): ProcessCompilerData = {
    val servicesDefs = definitionWithTypes.modelDefinition.components.components
      .filter(_.componentType == ComponentType.Service)

    val globalVariablesPreparer = GlobalVariablesPreparer(definitionWithTypes.modelDefinition.expressionConfig)
    val expressionEvaluator =
      ExpressionEvaluator.optimizedEvaluator(globalVariablesPreparer, listeners)

    val expressionCompiler = ExpressionCompiler.withOptimization(
      userCodeClassLoader,
      dictRegistry,
      definitionWithTypes.modelDefinition.expressionConfig,
      definitionWithTypes.classDefinitions,
      expressionEvaluator
    )

    // for testing environment it's important to take classloader from user jar
    val nodeCompiler = new NodeCompiler(
      definitionWithTypes.modelDefinition,
      new FragmentParametersDefinitionExtractor(userCodeClassLoader),
      expressionCompiler,
      userCodeClassLoader,
      listeners,
      resultsCollector,
      componentUseCase,
      nonServicesLazyParamStrategy
    )
    val subCompiler = new PartSubGraphCompiler(nodeCompiler)
    val processCompiler = new ProcessCompiler(
      userCodeClassLoader,
      subCompiler,
      globalVariablesPreparer,
      nodeCompiler,
      customProcessValidator
    )

    val interpreter = Interpreter(listeners, expressionEvaluator, componentUseCase)

    new ProcessCompilerData(
      processCompiler,
      subCompiler,
      expressionCompiler,
      expressionEvaluator,
      interpreter,
      listeners,
      jobData,
      servicesDefs.map(service => service.name -> service.component.asInstanceOf[Lifecycle]).toMap
    )

  }

}

final class ProcessCompilerData(
    compiler: ProcessCompiler,
    val subPartCompiler: PartSubGraphCompiler,
    val expressionCompiler: ExpressionCompiler,
    val expressionEvaluator: ExpressionEvaluator,
    val interpreter: Interpreter,
    val listeners: Seq[ProcessListener],
    val jobData: JobData,
    services: Map[String, Lifecycle]
) {

  def lifecycle(nodesToUse: List[_ <: NodeData]): Seq[Lifecycle] = {
    val componentIds = nodesToUse.collect { case e: WithComponent =>
      e.componentId
    }
    // TODO: For eager services we should open service implementation (ServiceInvoker) which is hold inside
    //       SyncInterpretationFunction.compiledNode inside ServiceRef instead of definition (DynamicComponent)
    //       Definition shouldn't be used after component is compiled. Thanks to that it will be possible to
    //       e.g. to pass ExecutionContext inside EngineRuntimeContext and to separate implementation from definition
    val servicesToUse = services.filterKeysNow(componentIds.contains).values
    listeners ++ servicesToUse
  }

  def compile(process: CanonicalProcess): ValidatedNel[ProcessCompilationError, CompiledProcessParts] =
    compiler.compile(process)(jobData).result
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy