Filters can be chained together with the “andThen” function. This is essentially an indicator of which direction the Request (input) is handed off to the next filter. I believe that when we normally think about filters, we expect the filter to act on the Request (like a sieve, for example), and indeed it can. However, once the Request gets to the end of the Filter chain, it gets turned into a Response (output), which also, in turn, can be filtered as it is passed back back to the beginning of the Filter chain.
Here is a ScalaTest that shows how both the inward and outward paths can be used to modify the request and the response, as well as a short-circuit in Filter3 that prevents Filter4 from being run (you can change the condition to true to see the path through all four filters). The example Finagle Service here simply takes an initial value and concatenates the request to make a Response:
import com.twitter.finagle.{Service, SimpleFilter} import com.twitter.util.Future import org.scalatest._ class StringService(response: String) extends Service[String, String] { override def apply(request: String): Future[String] = Future.value(response + ":" + request) } object StringFilter1 extends SimpleFilter[String, String] { override def apply(request: String, service: Service[String, String]): Future[String] = { val requestUpdate = request.concat(" » enter-1") service(requestUpdate).map(futureString => futureString.concat(" » exit-1")) } } object StringFilter2 extends SimpleFilter[String, String] { override def apply(request: String, service: Service[String, String]): Future[String] = { val requestUpdate = request.concat(" » enter-2") service(requestUpdate).map(futureString => futureString.concat(" » exit-2")) } } object StringFilter3 extends SimpleFilter[String, String] { override def apply(request: String, service: Service[String, String]): Future[String] = { val requestUpdate = request.concat(" » enter-3") val myCondition = false if(myCondition){ service(requestUpdate).map(futureString => futureString.concat(" » exit-3")) } else { Future(requestUpdate.concat(" » short-circuit-3")) } } } object StringFilter4 extends SimpleFilter[String, String] { override def apply(request: String, service: Service[String, String]): Future[String] = { val requestUpdate = request.concat(" » enter-4") service(requestUpdate).map(futureString => futureString.concat(" » exit-4")) } } class FilterStackTest extends FlatSpec with Matchers { "A Filter" should "Operate like a Stack" in { var testService = new StringService("Service A") var testFilter = StringFilter1 andThen StringFilter2 andThen StringFilter3 andThen StringFilter4 System.out.println(testFilter("start",testService)) } }
The console output is:
Promise@71098046(state=Done(Return(start » enter-1 » enter-2 » enter-3 » short-circuit-3 » exit-2 » exit-1)))
And when val myCondition = true :
Promise@380962452(state=Done(Return(Service A:start » enter-1 » enter-2 » enter-3 » enter-4 » exit-4 » exit-3 » exit-2 » exit-1)))
No comments:
Post a Comment