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

pl.touk.nussknacker.engine.definition.component.Components.scala Maven / Gradle / Ivy

The newest version!
package pl.touk.nussknacker.engine.definition.component

import pl.touk.nussknacker.engine.api.component._
import pl.touk.nussknacker.engine.definition.model.DuplicatedComponentsException
import pl.touk.nussknacker.engine.modelconfig.ComponentsUiConfig
import pl.touk.nussknacker.engine.util.Implicits.RichTupleList

final case class Components private (
    components: List[ComponentDefinitionWithImplementation],
    // component definitions not enriched with ui config
    private val basicComponents: Option[List[ComponentDefinitionWithImplementation]]
) {

  def withComponents(componentsToAdd: List[ComponentDefinitionWithImplementation]): Components = {
    val newComponents = copy(
      components = components ::: componentsToAdd,
      basicComponents = basicComponents.map(values => values ::: componentsToAdd)
    )
    Components.validated(newComponents)
  }

  def withComponents(componentsToAdd: Components): Components = {
    val newComponents = Components.combine(this, componentsToAdd)
    Components.validated(newComponents)
  }

  def filter(predicate: ComponentDefinitionWithImplementation => Boolean): Components = {
    copy(
      components = components.filter(predicate),
      basicComponents = basicComponents.map(_.filter(predicate)),
    )
  }

  def basicComponentsUnsafe: List[ComponentDefinitionWithImplementation] =
    basicComponents.getOrElse(
      throw new IllegalStateException("Basic components requested but they are not precomputed")
    )

}

object Components {

  sealed trait ComponentDefinitionExtractionMode {
    def extractBasicDefinitions: Boolean
  }

  object ComponentDefinitionExtractionMode {

    case object FinalDefinition extends ComponentDefinitionExtractionMode {
      override def extractBasicDefinitions: Boolean = false
    }

    case object FinalAndBasicDefinitions extends ComponentDefinitionExtractionMode {
      override def extractBasicDefinitions: Boolean = true
    }

  }

  def empty(mode: ComponentDefinitionExtractionMode): Components = new Components(
    components = List.empty,
    basicComponents = if (mode.extractBasicDefinitions) Some(List.empty) else None
  )

  def apply(
      components: List[ComponentDefinitionWithImplementation],
      basicComponents: Option[List[ComponentDefinitionWithImplementation]]
  ): Components = {
    val newComponents = new Components(components, basicComponents)
    validated(newComponents)
  }

  def withComponent(
      componentName: String,
      component: Component,
      configFromDefinition: ComponentConfig,
      componentsUiConfig: ComponentsUiConfig,
      determineDesignerWideId: ComponentId => DesignerWideComponentId,
      additionalConfigsFromProvider: Map[DesignerWideComponentId, ComponentAdditionalConfig],
      componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
  ): Components = {

    def extractComponentDefinition(
        uiConfig: ComponentsUiConfig,
        configFromProvider: Map[DesignerWideComponentId, ComponentAdditionalConfig]
    ) = {
      ComponentDefinitionExtractor
        .extract(
          componentName,
          component,
          configFromDefinition,
          uiConfig,
          determineDesignerWideId,
          configFromProvider
        )
    }

    Components(
      components = extractComponentDefinition(componentsUiConfig, additionalConfigsFromProvider).toList,
      basicComponents =
        if (componentDefinitionExtractionMode.extractBasicDefinitions)
          Some(extractComponentDefinition(uiConfig = ComponentsUiConfig.Empty, configFromProvider = Map.empty).toList)
        else
          None
    )
  }

  def forList(
      components: List[ComponentDefinition],
      componentsUiConfig: ComponentsUiConfig,
      determineDesignerWideId: ComponentId => DesignerWideComponentId,
      additionalConfigsFromProvider: Map[DesignerWideComponentId, ComponentAdditionalConfig],
      componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
  ): Components = {

    def extractComponentDefinitions(
        uiConfig: ComponentsUiConfig,
        configFromProvider: Map[DesignerWideComponentId, ComponentAdditionalConfig]
    ) = {
      ComponentDefinitionWithImplementation.forList(
        components,
        uiConfig,
        determineDesignerWideId,
        configFromProvider
      )
    }

    Components(
      components = extractComponentDefinitions(componentsUiConfig, additionalConfigsFromProvider).toList,
      basicComponents =
        if (componentDefinitionExtractionMode.extractBasicDefinitions)
          Some(
            extractComponentDefinitions(uiConfig = ComponentsUiConfig.Empty, configFromProvider = Map.empty).toList
          )
        else
          None
    )
  }

  def fold(
      componentDefinitionExtractionMode: ComponentDefinitionExtractionMode,
      components: List[Components]
  ): Components = {
    validated(components.foldLeft(Components.empty(componentDefinitionExtractionMode))(Components.combine))
  }

  private def validated(components: Components): Components = {
    checkDuplicates(components)
    components
  }

  private def checkDuplicates(components: Components): Unit = {
    def findDuplicates(values: List[ComponentDefinitionWithImplementation]) = {
      values
        .map(component => component.id -> component)
        .toGroupedMap
        .filter(_._2.size > 1)
        .keys
        .toList
        .sorted
    }

    val componentsDuplicates      = findDuplicates(components.components)
    val basicComponentsDuplicates = components.basicComponents.map(findDuplicates).getOrElse(List.empty)

    if (componentsDuplicates.nonEmpty) {
      throw new DuplicatedComponentsException(componentsDuplicates)
    } else if (basicComponentsDuplicates.nonEmpty) {
      throw new DuplicatedComponentsException(basicComponentsDuplicates)
    }
  }

  private def combine(x: Components, y: Components): Components = {
    x.copy(
      components = x.components ::: y.components,
      basicComponents = x.basicComponents.map(components => components ::: y.basicComponents.getOrElse(List.empty)),
    )
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy