From the «Functional Programming Patterns» book.
package com.mblinn.mbfpp.oo.tinyweb
import scala.util.Random
/**
* Created by IDEA on 25/10/15.
*/
object Stepfour {
import com.mblinn.oo.tinyweb.{ControllerException, RenderingException}
type Model = Map[String, List[String]]
trait View {
def render(model: Model): String
}
class FunctionView(viewRenderer: (Model) => String) extends View {
def render(model: Map[String, List[String]]) =
try
viewRenderer(model)
catch {
case e: Exception => throw new RenderingException(e)
}
}
case class HttpRequest(headers: Model = Map(), body: String, path: String)
case class HttpResponse(body: String, responseCode: Integer)
trait Controller {
def handleRequest(httpRequest: HttpRequest): HttpResponse
}
class FunctionController(view: View, doRequest: (HttpRequest) =>
Model) extends Controller {
def handleRequest(request: HttpRequest): HttpResponse =
try {
val model = doRequest(request)
val responseBody = view.render(model)
HttpResponse(responseBody, 200)
} catch {
case e: ControllerException =>
HttpResponse("", e.getStatusCode)
case e: RenderingException =>
HttpResponse("Exception while rendering.", 500)
case e: Exception =>
HttpResponse("", 500)
}
}
class TinyWeb(controllers: Map[String, Controller],
filters: List[(HttpRequest) => HttpRequest]) {
def handleRequest(httpRequest: HttpRequest): Option[HttpResponse] = {
val composedFilter = filters.reverse.reduceLeft(
(composed, next) => composed compose next)
val filteredRequest = composedFilter(httpRequest)
val controllerOption = controllers.get(filteredRequest.path)
controllerOption map { controller => controller.handleRequest(filteredRequest) }
}
}
}
object Test {
import Stepfour._
// generate a view
def renderGreeting(greeting: String) = {
"<h2>%s</h2>".format(greeting)
}
def greetingViewRenderer(model: Model) =
"<h1>Friendly Greetings: %s</h1>".format(
model.getOrElse("greetings", List.empty[String])
.map(renderGreeting)
.mkString(" ")
)
def greetingView = new FunctionView(greetingViewRenderer) // generate a view end
// generate a model
import scala.util.Random
def random = new Random()
val greetings = List("Hi", "Hoi", "Hola", "Bonjour")
def makeGreeting(name: String): String = {
"%s, %s".format(greetings(random.nextInt(greetings.size)), name)
}
def handleGreetingRequest(request: HttpRequest): Model = {
Map("greetings" -> request.body.split(",").toList.map(makeGreeting))
} // generate a model end
// controller
def greetingController = new FunctionController(greetingView, handleGreetingRequest) // controller end
def loggingFilter(request: HttpRequest) = {
println("In Logging Filter - request for path: %s".format(request.path))
request
}
def tinyweb = new TinyWeb(
Map("/greeting" -> greetingController),
List(loggingFilter))
def testHttpRequest = HttpRequest(
body="Mike,Joe,John,Steve",
path="/greeting")
tinyweb.handleRequest(testHttpRequest).get.body
}
0 comments:
Post a Comment