Play2 Action Grooming

Source: Internet
Author: User
Tags throw exception

The reason to study it is to use it to provide, ActionBuilder ActionFilter when, feel the ActionTransform API is not flexible enough to provide.

Play encapsulates the process for background processing of the foreground request Handler , and we'll look at the HTTP section first. It's just looking down Action .

Action

Here are Action some of trait's information

trait EssentialAction extends (RequestHeader => Iteratee[Array[Byte], Result]) with Handler trait Action[A] extends EssentialAction {    /**   * Type of the request body.   */  type BODY_CONTENT = A  /**   * Body parser associated with this action.   */  def parser: BodyParser[A]  /**   * Invokes this action.   *   * @param request the incoming HTTP request   * @return the result to be sent to the client   */  def apply(request: Request[A]): Future[Result]  def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] ...//下面的省略}

ActionInheritance Function1[RequestHeader,Iteratee[Array[Byte], Result]] , in other words, Action is actually a function. This gives play a natural and asynchronous grammatical advantage.
?

Bodyparser

BodyParseris the main processing of the HTTP report body (as for the URI is stored in the Requestheader) is the business logic processing function storage place, the following is the BodyParser inheritance relationship

BodyParserThe return result of the function is that Either[Result,A] the benefit of this is to keep the business logic chained, and to return to result at any time (especially when the throw exception), without any further processing.
BodyParserIn Monad the way of programming, it is worth noting that play has added mapM flatMapM two functions to Async

def mapM[B](f: A => Future[B])(implicit ec: ExecutionContext): BodyParser[B]def flatMapM[B](f: A => Future[BodyParser[B]])(implicit ec: ExecutionContext): BodyParser[B]

As for

def validate[B](f: A => Either[Result, B])(implicit ec: ExecutionContext): BodyParser[B]def validateM[B](f: A => Future[Either[Result, B]])(implicit ec: ExecutionContext): BodyParser[B]

is implemented on the basis of implementation flatMap flatMapM . Choose to validateM look down

def validateM[B](f: A => Future[Either[Result, B]])(implicit ec: ExecutionContext): BodyParser[B] = {    // prepare execution context as body parser object may cross thread boundary    implicit val pec = ec.prepare()    new BodyParser[B] {//scala中的链式基本上是生成新实例来保持Immutable      def apply(request: RequestHeader) = self(request).flatMapM {        case Right(a) =>          // safe to execute `Done.apply` in same thread          f(a).map(Done.apply[Array[Byte], Either[Result, B]](_))(Execution.trampoline)        case left => //当Left时,直接包装成返回结果          Future.successful {            Done[Array[Byte], Either[Result, B]](left.asInstanceOf[Either[Result, B]])          }      }(pec)      override def toString = self.toString    }  }

As for the praised abstraction in play Iteratee , you can refer to this blog Understanding-play2-iteratees-for-normal-humans.

Actionbuilder

In our actual application, Action there is an asynchronous and a synchronous

val name1=Action{implicit request=>//同步    ...}val name2=Action.async{implicit request=>//异步    ...}

In fact, synchronization is implemented asynchronously. In the future of Scala, the method of synchronizing mutation steps is generally

Future.successful(action)Future.failed(action)

Because async the method of writing, the individual can not understand why so write, so first get a simplified version async , easy to understand.

Simplified ' actionbuilder ' ' async ' method def Async[a] (Bodyparser:bodyparser[a]) (block:r[a] [= Future[result]): action[a] = New Action[a] {//class name Actionbuilder Genuine def parser = Bodyparser def apply (request:request[a]) = try {Invokebloc  K (Request, block)} catch {case e:exception = throw new Exception ("...") override def ExecutionContext = ActionBuilder.this.executionContext})//actual ' async ' method final def Async[a] (Bodyparser:bodyparser[a]) (block:r[a] =  Future[result]): action[a] = composeaction (new Action[a] {def parser = Composeparser (Bodyparser) def apply (Request: Request[a]) = try {Invokeblock (Request, block)} catch {//Notimplementederror is not caught by nonfatal,  Wrap it case e:notimplementederror = throw new RuntimeException (e)//Linkageerror is similarly harmless in Play Framework, since automatic reloading could easily trigger it case e:linkageerror = throw new runtimeexcept Ion (E)} override def execUtioncontext = ActionBuilder.this.executionContext}) 

The actual source code in the async method has the final keyword, which led us to override,play the team may be based on this layer of consideration, burst out
The following two methods are used as rewrite compensation

protected def composeAction[A](action: Action[A]): Action[A] =actionprotected def composeParser[A](bodyParser: BodyParser[A]): BodyParser[A] =bodyParser
Actionfilter

ActionFilterPlay the role of the Interceptor, through the compose to and assemble, but does not support or the assembly (when encountering the rights filter combination, it can not be used), this can not be said not a pity, I write a play first.

trait RichFilterAction[R[_]] extends ActionRefiner[R, R] { self =>  def filter[A](request: R[A]): Future[Option[Result]]  protected final def refine[A](request: R[A]): Future[Either[Result, R[A]]] =    filter(request).map(_.toLeft(request))(executionContext)  def orElse(other: RichFilterAction[R]) = new RichFilterAction[R] {    def filter[A](request: R[A]): Future[Option[Result]] = {      self.filter(request).flatMap {        case Some(result) => other.filter(request)        case None         => Future.successful(None)      }(executionContext)    }  }}
Actiontransformer

As the name implies, the input type is converted to another type of output, and at the semantic level, do not use it to deal with side-effects conversions. When faced with side effects of the conversion requirements, the first to actionfilter filter out the side effects, and then use ActionTransformer to do

Actionfunction

ActionFilterActionBuilder ActionTransfer are inherited Action . And in a specific logical implementation of the method, put it on the final keyword, to prevent user abuse invokeBlock methods, destruction ActionFilter , ActionBuilder ActionTransfer the semantics.
ActionFunctionThe Compose,andthen method (which is used as an API with the same name in Function1) is also provided to guarantee chaining.

Play2 Action Grooming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.