Richard Searle

home

Recursive PartialFunctions for Choreography

28 Mar 2011

The core of an Actor is the receive function, which is a PartialFunction over the expected inputs to the actor. The remainder of actor is largely boilerplate, concerned with implementation details. Our choreography DSL must be built around the process of building a PartialFunction that implements the composite service. An interaction with a sub-service might be expressed as a function (A)=>CorrelationID which represents starting of a request/response MEP over the JMS queue. This function exposes an implementation detail (the CorrelationID) and does not capture the type of the expected response. That type would allow Scala to automatically provide useful service, such as automatic wiring via implicit values. It also provides type safety and documentation. The response once received will be processed by some function, which can be expressed as part of the sub-service function (A)=>(R)=>X, where R is the type of the response and X is the final result. We have now captured both types that participate in the sub-service interaction and tied it into the workflow that it drives. The key question is then:What is X? In general, the consuming function will perform further sub-service interactions with their own consuming functions! X is thus a PartialFunction that returns values that have type X. Such recursion must eventually terminate with the final result of the composite service. A special type will be used for that purpose, using the Option idiom
trait RPF extends PartialFunction[CI, Any=>RPF]
trait Lookup[A,R] {
 def apply(arg:A)(fn:R =>RPF):RPF = ...
}
case class Result[A](value:A) extends RPF{...}
The composite workflow can now be written as
object SingleLineBalance{
   def apply(pn:Num)(implicit acctLook:Lookup[Num,Acct],  balLook:Lookup[Acct,Bal]) =
   {
         acctLook(pn){balLook(_)(Result(_))}
   }
}
The Lookups representing the sub-services are specified as implicits so they can be "automatically wired" at the point the object is used. Note that SingleLineBalance is not itself the workflow but rather returns a function that is the implementation. It can be read: This is a faithful representation of the original business process, with minimal boilerplate.