Skip to content

Commit

Permalink
[NU-1847] Definition service with the ability to return definition wi…
Browse files Browse the repository at this point in the history
…thout config from additional provider (#7021)
  • Loading branch information
mateuszkp96 authored Oct 29, 2024
1 parent 84657ca commit 24c3b0c
Show file tree
Hide file tree
Showing 53 changed files with 746 additions and 257 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import pl.touk.nussknacker.engine.api.process._
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess
import pl.touk.nussknacker.engine.compile.ProcessCompilerData
import pl.touk.nussknacker.engine.compiledgraph.part.ProcessPart
import pl.touk.nussknacker.engine.definition.component.ComponentDefinitionWithImplementation
import pl.touk.nussknacker.engine.definition.component.Components.ComponentDefinitionExtractionMode
import pl.touk.nussknacker.engine.definition.component.{ComponentDefinitionWithImplementation, Components}
import pl.touk.nussknacker.engine.definition.model.{ModelDefinition, ModelDefinitionWithClasses}
import pl.touk.nussknacker.engine.dict.SimpleDictRegistry
import pl.touk.nussknacker.engine.modelconfig.ComponentsUiConfig
Expand Down Expand Up @@ -52,8 +53,14 @@ class InterpreterSetup[T: ClassTag] {
) ::: additionalComponents

val definitions = ModelDefinition(
ComponentDefinitionWithImplementation
.forList(components, ComponentsUiConfig.Empty, id => DesignerWideComponentId(id.toString), Map.empty),
Components
.forList(
components,
ComponentsUiConfig.Empty,
id => DesignerWideComponentId(id.toString),
Map.empty,
ComponentDefinitionExtractionMode.FinalDefinition
),
ModelDefinitionBuilder.emptyExpressionConfig,
ClassExtractionSettings.Default
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ package object definition {
// should be invalidated
branchParam: Boolean,
hintText: Option[String],
label: String
label: String,
// This attribute is used only by external project
requiredParam: Boolean,
)

@JsonCodec(encodeOnly = true) final case class UIComponentDefinition(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package pl.touk.nussknacker.ui.api

import akka.http.scaladsl.model._
import akka.http.scaladsl.server.{Directives, Route}
import akka.http.scaladsl.server.{Directive1, Directives, Route}
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import pl.touk.nussknacker.ui.definition.DefinitionsService
import pl.touk.nussknacker.ui.definition.DefinitionsService.ComponentUiConfigMode
import pl.touk.nussknacker.ui.process.processingtype.provider.ProcessingTypeDataProvider
import pl.touk.nussknacker.ui.security.api.LoggedUser
import pl.touk.nussknacker.ui.util.NuPathMatchers
Expand All @@ -25,8 +26,8 @@ class DefinitionResources(
.map { case (definitionsService) =>
pathEndOrSingleSlash {
get {
parameter(Symbol("isFragment").as[Boolean]) { isFragment =>
complete(definitionsService.prepareUIDefinitions(processingType, isFragment))
(isFragmentParam & componentUiConfigModeParam) { (isFragment, componentUiConfigMode) =>
complete(definitionsService.prepareUIDefinitions(processingType, isFragment, componentUiConfigMode))
}
}
}
Expand All @@ -37,4 +38,14 @@ class DefinitionResources(
}
}

private val isFragmentParam: Directive1[Boolean] = parameter(Symbol("isFragment").as[Boolean])

private val componentUiConfigModeParam: Directive1[ComponentUiConfigMode] = {
// parameter used only by an external project to fetch component definitions without enrichments
parameter("enrichedWithUiConfig".as[Boolean].optional).flatMap {
case Some(true) | None => provide(ComponentUiConfigMode.EnrichedWithUiConfig)
case Some(false) => provide(ComponentUiConfigMode.BasicConfig)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cats.data.Validated.{Invalid, Valid}
import com.typesafe.config.Config
import com.typesafe.scalalogging.LazyLogging
import net.ceedubs.ficus.readers.ValueReader
import pl.touk.nussknacker.engine.definition.component.Components.ComponentDefinitionExtractionMode
import pl.touk.nussknacker.engine.util.config.FicusReaders
import pl.touk.nussknacker.ui.api._
import pl.touk.nussknacker.ui.config.Implicits.parseOptionalConfig
Expand All @@ -27,6 +28,7 @@ final case class FeatureTogglesConfig(
testDataSettings: TestDataSettings,
enableConfigEndpoint: Boolean,
redirectAfterArchive: Boolean,
componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
)

object FeatureTogglesConfig extends LazyLogging {
Expand Down Expand Up @@ -55,6 +57,7 @@ object FeatureTogglesConfig extends LazyLogging {
val intervalTimeSettings = config.as[IntervalTimeSettings]("intervalTimeSettings")
val testDataSettings = config.as[TestDataSettings]("testDataSettings")
val redirectAfterArchive = config.getAs[Boolean]("redirectAfterArchive").getOrElse(true)
val componentDefinitionExtractionMode = parseComponentDefinitionExtractionMode(config)

FeatureTogglesConfig(
development = isDevelopmentMode,
Expand All @@ -72,6 +75,7 @@ object FeatureTogglesConfig extends LazyLogging {
testDataSettings = testDataSettings,
enableConfigEndpoint = enableConfigEndpoint,
redirectAfterArchive = redirectAfterArchive,
componentDefinitionExtractionMode = componentDefinitionExtractionMode,
)
}

Expand All @@ -90,4 +94,13 @@ object FeatureTogglesConfig extends LazyLogging {
}
}

private def parseComponentDefinitionExtractionMode(config: Config): ComponentDefinitionExtractionMode = {
val configPath = "enableBasicDefinitionsForComponents"
if (config.hasPath(configPath) && config.getBoolean(configPath)) {
ComponentDefinitionExtractionMode.FinalAndBasicDefinitions
} else {
ComponentDefinitionExtractionMode.FinalDefinition
}
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package pl.touk.nussknacker.ui.definition

import cats.data.NonEmptySet
import pl.touk.nussknacker.engine.ModelData
import pl.touk.nussknacker.engine.api.component.Component.AllowedProcessingModes
import pl.touk.nussknacker.engine.api.component.{ComponentType, ProcessingMode}
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess
import pl.touk.nussknacker.engine.definition.component.ComponentDefinitionWithImplementation
import pl.touk.nussknacker.engine.definition.component.{ComponentDefinitionWithImplementation, Components}
import pl.touk.nussknacker.engine.definition.component.bultin.BuiltInComponentsDefinitionsPreparer
import pl.touk.nussknacker.engine.definition.fragment.FragmentComponentDefinitionExtractor
import pl.touk.nussknacker.engine.definition.model.ModelDefinition
Expand All @@ -21,7 +19,7 @@ class AlignedComponentsDefinitionProvider(
def getAlignedComponentsWithBuiltInComponentsAndFragments(
forFragment: Boolean,
fragments: List[CanonicalProcess],
): List[ComponentDefinitionWithImplementation] = {
): Components = {
val filteredModel = if (forFragment) {
modelDefinition
.filterComponents(_.componentType != ComponentType.Source)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import pl.touk.nussknacker.engine.definition.component.{ComponentStaticDefinitio
import pl.touk.nussknacker.engine.util.Implicits.RichScalaMap
import pl.touk.nussknacker.engine.ModelData
import pl.touk.nussknacker.restmodel.definition._
import pl.touk.nussknacker.ui.definition.DefinitionsService.{createUIParameter, createUIScenarioPropertyConfig}
import pl.touk.nussknacker.ui.definition.DefinitionsService.{
ComponentUiConfigMode,
createUIParameter,
createUIScenarioPropertyConfig
}
import pl.touk.nussknacker.ui.definition.component.{ComponentGroupsPreparer, ComponentWithStaticDefinition}
import pl.touk.nussknacker.ui.definition.scenarioproperty.{FragmentPropertiesConfig, UiScenarioPropertyEditorDeterminer}
import pl.touk.nussknacker.ui.process.fragment.FragmentRepository
import pl.touk.nussknacker.ui.process.processingtype.ProcessingTypeData
import pl.touk.nussknacker.ui.process.processingtype.{DesignerModelData, ProcessingTypeData}
import pl.touk.nussknacker.ui.security.api.LoggedUser

import scala.concurrent.{ExecutionContext, Future}
Expand All @@ -23,7 +27,7 @@ import scala.concurrent.{ExecutionContext, Future}
// enters the scenario view. The core domain logic should be done during Model definition extraction
class DefinitionsService(
modelData: ModelData,
staticDefinitionForDynamicComponents: Map[ComponentId, ComponentStaticDefinition],
staticDefinitionForDynamicComponents: DesignerModelData.DynamicComponentsStaticDefinitions,
scenarioPropertiesConfig: Map[String, ScenarioPropertyConfig],
fragmentPropertiesConfig: Map[String, ScenarioPropertyConfig],
deploymentManager: DeploymentManager,
Expand All @@ -33,29 +37,51 @@ class DefinitionsService(
fragmentPropertiesDocsUrl: Option[String]
)(implicit ec: ExecutionContext) {

def prepareUIDefinitions(processingType: ProcessingType, forFragment: Boolean)(
def prepareUIDefinitions(
processingType: ProcessingType,
forFragment: Boolean,
componentUiConfigMode: ComponentUiConfigMode
)(
implicit user: LoggedUser
): Future[UIDefinitions] = {
fragmentRepository.fetchLatestFragments(processingType).map { fragments =>
val alignedComponentsDefinition =
alignedComponentsDefinitionProvider
.getAlignedComponentsWithBuiltInComponentsAndFragments(forFragment, fragments)

val withStaticDefinition = alignedComponentsDefinition.map {
case dynamic: DynamicComponentDefinitionWithImplementation =>
val staticDefinition = staticDefinitionForDynamicComponents.getOrElse(
dynamic.id,
throw new IllegalStateException(s"Static definition for dynamic component: $dynamic should be precomputed")
)
ComponentWithStaticDefinition(dynamic, staticDefinition)
case methodBased: MethodBasedComponentDefinitionWithImplementation =>
ComponentWithStaticDefinition(methodBased, methodBased.staticDefinition)
case other =>
throw new IllegalStateException(s"Unknown component representation: $other")
val withStaticDefinition = {
val (components, cachedStaticDefinitionsForDynamicComponents) = componentUiConfigMode match {
case ComponentUiConfigMode.EnrichedWithUiConfig =>
(alignedComponentsDefinition.components, staticDefinitionForDynamicComponents.finalDefinitions)
case ComponentUiConfigMode.BasicConfig =>
(
alignedComponentsDefinition.basicComponentsUnsafe,
staticDefinitionForDynamicComponents.basicDefinitionsUnsafe
)
}

components.map {
case dynamic: DynamicComponentDefinitionWithImplementation =>
val staticDefinition = cachedStaticDefinitionsForDynamicComponents.getOrElse(
dynamic.id,
throw new IllegalStateException(
s"Static definition for dynamic component: $dynamic should be precomputed"
)
)
ComponentWithStaticDefinition(dynamic, staticDefinition)
case methodBased: MethodBasedComponentDefinitionWithImplementation =>
ComponentWithStaticDefinition(methodBased, methodBased.staticDefinition)
case other =>
throw new IllegalStateException(s"Unknown component representation: $other")
}
}

val finalizedScenarioPropertiesConfig = scenarioPropertiesConfigFinalizer
.finalizeScenarioProperties(scenarioPropertiesConfig)
val finalizedScenarioPropertiesConfig = componentUiConfigMode match {
case ComponentUiConfigMode.EnrichedWithUiConfig =>
scenarioPropertiesConfigFinalizer.finalizeScenarioProperties(scenarioPropertiesConfig)
case ComponentUiConfigMode.BasicConfig =>
scenarioPropertiesConfig
}

import net.ceedubs.ficus.Ficus._
val scenarioPropertiesDocsUrl = modelData.modelConfig.getAs[String]("scenarioPropertiesDocsUrl")
Expand Down Expand Up @@ -143,7 +169,8 @@ object DefinitionsService {
variablesToHide = parameter.variablesToHide,
branchParam = parameter.branchParam,
hintText = parameter.hintText,
label = parameter.label
label = parameter.label,
requiredParam = !parameter.isOptional,
)
}

Expand All @@ -152,4 +179,11 @@ object DefinitionsService {
UiScenarioPropertyConfig(config.defaultValue, editor, config.label, config.hintText)
}

sealed trait ComponentUiConfigMode

object ComponentUiConfigMode {
case object EnrichedWithUiConfig extends ComponentUiConfigMode
case object BasicConfig extends ComponentUiConfigMode
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class DefaultComponentService(
forFragment = false, // It excludes fragment's components: input / output
fragments
)
.components

private def createComponentLinks(
designerWideId: DesignerWideComponentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package pl.touk.nussknacker.ui.process.processingtype
import pl.touk.nussknacker.engine.ModelData
import pl.touk.nussknacker.engine.api.component.{ComponentId, ProcessingMode}
import pl.touk.nussknacker.engine.definition.component.ComponentStaticDefinition
import pl.touk.nussknacker.ui.process.processingtype.DesignerModelData.DynamicComponentsStaticDefinitions

final case class DesignerModelData(
modelData: ModelData,
// We hold this map as a cache - computing it is a quite costly operation (it invokes external services)
staticDefinitionForDynamicComponents: Map[ComponentId, ComponentStaticDefinition],
// We hold definitions as a cache - computing them is a quite costly operation (it invokes external services)
staticDefinitionForDynamicComponents: DynamicComponentsStaticDefinitions,
processingMode: ProcessingMode
) {

Expand All @@ -16,3 +17,20 @@ final case class DesignerModelData(
}

}

object DesignerModelData {

final case class DynamicComponentsStaticDefinitions(
finalDefinitions: Map[ComponentId, ComponentStaticDefinition],
// component definitions not enriched with ui config
private val basicDefinitions: Option[Map[ComponentId, ComponentStaticDefinition]]
) {

def basicDefinitionsUnsafe: Map[ComponentId, ComponentStaticDefinition] =
basicDefinitions.getOrElse(
throw new IllegalStateException("Basic definitions were requested but they are not precomputed")
)

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ import pl.touk.nussknacker.engine._
import pl.touk.nussknacker.engine.api.component.ScenarioPropertyConfig
import pl.touk.nussknacker.engine.api.deployment.cache.ScenarioStateCachingConfig
import pl.touk.nussknacker.engine.api.process.ProcessingType
import pl.touk.nussknacker.engine.definition.component.DynamicComponentStaticDefinitionDeterminer
import pl.touk.nussknacker.engine.definition.component.Components.ComponentDefinitionExtractionMode
import pl.touk.nussknacker.engine.definition.component.{
ComponentDefinitionWithImplementation,
Components,
DynamicComponentStaticDefinitionDeterminer
}
import pl.touk.nussknacker.engine.deployment.EngineSetupName
import pl.touk.nussknacker.restmodel.scenariodetails.ScenarioParameters
import pl.touk.nussknacker.ui.process.processingtype.DesignerModelData.DynamicComponentsStaticDefinitions

import scala.util.control.NonFatal

Expand Down Expand Up @@ -50,7 +56,8 @@ object ProcessingTypeData {
deploymentManagerDependencies: DeploymentManagerDependencies,
engineSetupName: EngineSetupName,
deploymentConfig: Config,
category: String
category: String,
componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
): ProcessingTypeData = {
try {
val metaDataInitializer = deploymentManagerProvider.metaDataInitializer(deploymentConfig)
Expand All @@ -64,7 +71,8 @@ object ProcessingTypeData {
metaDataInitializer
)

val designerModelData = createDesignerModelData(modelData, metaDataInitializer, name)
val designerModelData =
createDesignerModelData(modelData, metaDataInitializer, name, componentDefinitionExtractionMode)
ProcessingTypeData(
name,
designerModelData,
Expand Down Expand Up @@ -117,17 +125,42 @@ object ProcessingTypeData {
private def createDesignerModelData(
modelData: ModelData,
metaDataInitializer: MetaDataInitializer,
processingType: ProcessingType
processingType: ProcessingType,
componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
) = {

val staticDefinitionForDynamicComponents =
createDynamicComponentsStaticDefinitions(modelData, metaDataInitializer, componentDefinitionExtractionMode)

val singleProcessingMode =
ScenarioParametersDeterminer.determineProcessingMode(
modelData.modelDefinition.components.components,
processingType
)
DesignerModelData(modelData, staticDefinitionForDynamicComponents, singleProcessingMode)
}

private def createDynamicComponentsStaticDefinitions(
modelData: ModelData,
metaDataInitializer: MetaDataInitializer,
componentDefinitionExtractionMode: ComponentDefinitionExtractionMode
): DynamicComponentsStaticDefinitions = {
def createStaticDefinitions(extractComponents: Components => List[ComponentDefinitionWithImplementation]) = {
DynamicComponentStaticDefinitionDeterminer.collectStaticDefinitionsForDynamicComponents(
modelData,
metaDataInitializer.create(_, Map.empty)
metaDataInitializer.create(_, Map.empty),
extractComponents
)
}

val singleProcessingMode =
ScenarioParametersDeterminer.determineProcessingMode(modelData.modelDefinition.components, processingType)
DesignerModelData(modelData, staticDefinitionForDynamicComponents, singleProcessingMode)
DynamicComponentsStaticDefinitions(
finalDefinitions = createStaticDefinitions(_.components),
basicDefinitions = componentDefinitionExtractionMode match {
case ComponentDefinitionExtractionMode.FinalDefinition => None
case ComponentDefinitionExtractionMode.FinalAndBasicDefinitions =>
Some(createStaticDefinitions(_.basicComponentsUnsafe))
}
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class LocalProcessingTypeDataLoader(
engineSetupName = deploymentManagerProvider.defaultEngineSetupName,
deploymentConfig = ConfigFactory.empty(),
category = category,
componentDefinitionExtractionMode = getModelDependencies(processingType).componentDefinitionExtractionMode
)
processingType -> data
}
Expand Down
Loading

0 comments on commit 24c3b0c

Please sign in to comment.