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

pl.touk.nussknacker.engine.split.ProcessSplitter.scala Maven / Gradle / Ivy

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

import pl.touk.nussknacker.engine.graph.EspProcess
import pl.touk.nussknacker.engine.graph.node._
import pl.touk.nussknacker.engine.splittedgraph._
import pl.touk.nussknacker.engine.splittedgraph.end.{DeadEnd, End, NormalEnd}
import pl.touk.nussknacker.engine.splittedgraph.part._
import pl.touk.nussknacker.engine.splittedgraph.splittednode.{NextNode, PartRef}

//NOTE: logic of splitter should match logic in SplittedNodesCollector
object ProcessSplitter {

  def split(process: EspProcess): SplittedProcess = {
    SplittedProcess(process.metaData, process.roots.map(split))
  }

  private def split(node: SourceNode): SourcePart = {
    val nextWithParts = traverse(node.next)
    SourcePart(splittednode.SourceNode(node.data, nextWithParts.next), nextWithParts.nextParts, nextWithParts.ends)
  }

  private def split(custom: CustomNode, next: SubsequentNode): CustomNodePart = {
    val nextWithParts = traverse(next)
    val node          = splittednode.OneOutputSubsequentNode(custom, nextWithParts.next)
    CustomNodePart(node, nextWithParts.nextParts, nextWithParts.ends)
  }

  private def split(custom: CustomNode): CustomNodePart = {
    val node = splittednode.EndingNode(custom)
    CustomNodePart(node, List.empty, List.empty)
  }

  private def split(sink: Sink): SinkPart = {
    val node = splittednode.EndingNode(sink)
    SinkPart(node)
  }

  private def traverse(node: SubsequentNode): NextWithParts =
    node match {
      case FilterNode(data, nextTrue, nextFalse) =>
        (nextTrue.map(traverse), nextFalse.map(traverse)) match {
          case (Some(nextTrueT), Some(nextFalseT)) =>
            NextWithParts(
              NextNode(splittednode.FilterNode(data, Some(nextTrueT.next), Some(nextFalseT.next))),
              nextTrueT.nextParts ::: nextFalseT.nextParts,
              nextTrueT.ends ::: nextFalseT.ends
            )
          case (None, Some(nextFalseT)) =>
            NextWithParts(
              NextNode(splittednode.FilterNode(data, None, Some(nextFalseT.next))),
              nextFalseT.nextParts,
              DeadEnd(data.id) :: nextFalseT.ends
            )
          case (Some(nextTrueT), None) =>
            NextWithParts(
              NextNode(splittednode.FilterNode(data, Some(nextTrueT.next), None)),
              nextTrueT.nextParts,
              DeadEnd(data.id) :: nextTrueT.ends
            )
          case (None, None) => throw new IllegalStateException("should not happen")
        }
      case SwitchNode(data, nexts, defaultNext) =>
        val (nextsT, casesNextParts, casesEnds) = nexts.map { casee =>
          val nextWithParts = traverse(casee.node)
          (splittednode.Case(casee.expression, nextWithParts.next), nextWithParts.nextParts, nextWithParts.ends)
        }.unzip3
        defaultNext.map(traverse) match {
          case Some(defaultNextT) =>
            NextWithParts(
              NextNode(splittednode.SwitchNode(data, nextsT, Some(defaultNextT.next))),
              defaultNextT.nextParts ::: casesNextParts.flatten,
              defaultNextT.ends ::: casesEnds.flatten
            )
          case None =>
            NextWithParts(
              NextNode(splittednode.SwitchNode(data, nextsT, None)),
              casesNextParts.flatten,
              DeadEnd(data.id) :: casesEnds.flatten
            )
        }
      case OneOutputSubsequentNode(custom: CustomNode, next) =>
        val part = split(custom, next)
        NextWithParts(PartRef(part.id), List(part), List.empty)
      case split: SplitNode =>
        val nextWithParts = split.nextParts.map(traverse)
        val node          = splittednode.SplitNode(split.data, nextWithParts.map(_.next))
        NextWithParts(NextNode(node), nextWithParts.flatMap(_.nextParts), nextWithParts.flatMap(_.ends))
      case OneOutputSubsequentNode(other, next) =>
        traverse(next).map { nextT =>
          NextNode(splittednode.OneOutputSubsequentNode(other, nextT))
        }
      case EndingNode(sink: Sink) =>
        val part = split(sink)
        NextWithParts(PartRef(sink.id), List(part), List.empty)
      case EndingNode(endingCustomNode: CustomNode) =>
        val part = split(endingCustomNode)
        NextWithParts(PartRef(part.id), List(part), List.empty)
      case EndingNode(other) =>
        NextWithParts(NextNode(splittednode.EndingNode(other)), List.empty, List(NormalEnd(other.id)))
      case BranchEnd(branchEndData) =>
        NextWithParts(
          NextNode(splittednode.EndingNode(branchEndData)),
          List.empty,
          List(end.BranchEnd(branchEndData.definition))
        )
      case FragmentNode(id, _) =>
        throw new RuntimeException("Should not happen")

    }

  case class NextWithParts(next: splittednode.Next, nextParts: List[SubsequentPart], ends: List[End]) {

    def map(f: splittednode.Next => splittednode.Next): NextWithParts = {
      copy(next = f(next))
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy