Class Acteur

java.lang.Object
com.mastfrog.acteurbase.AbstractActeur<Response,com.mastfrog.acteur.ResponseImpl,State>
com.mastfrog.acteur.Acteur
Direct Known Subclasses:
AuthenticationActeur, CheckIfModifiedSinceHeader, CheckIfNoneMatchHeader, CheckIfUnmodifiedSinceHeader, DeferredComputationResultActeur, InstallChunkHandler, WebSocketUpgradeActeur

public abstract class Acteur extends AbstractActeur<Response,com.mastfrog.acteur.ResponseImpl,State>
A single piece of logic which can
  • Reject an HTTP request
  • Validate an HTTP request and allow the next Acteur in the chain to process it
  • Initiate an HTTP response
Acteurs are aggregated into a list in a Page. All of an Acteur's work happens either in its constructor, prior to a call to setState(), or in its overridden getState() method. The state determines whether processing of the current list of Acteurs will continue, or if not, what happens to it.

Acteurs are constructed by Guice - in fact, what a Page has is usually just a list of classes. Objects they need, such as the current request HttpEvent can simply be constructor parameters if the constructor is annotated with Guice's @Inject.

An Acteur may construct some objects which will then be included in the set of objects the next Acteur in the chain can request for injection in its constructor parameters.

A number of inner classes are provided which can be used as standard states.

Acteurs may be - in fact, are likely to be - called asynchronously. For a given page, they will always be called in the sequence that page lists them in, but there is no guarantee that any two adjacent Acteurs will be called on the same thread. Any shared state should take the form of objects put into the context when the output State is created.

This makes it possible to incrementally respond to a request, for example, doing just enough computation to determine if a NOT MODIFIED response is possible without computing the complete response (which in that case would be thrown away).

Their asynchronous nature means that many requests can be handled simultaneously and run small bits of logic, interleaved, on fewer threads, for maximum throughput.

Support for asynchronous computation

Acteurs are asynchronous in nature, but by default the framework assumes they can be run one after the other. In the case an Acteur needs to call out to some library (perhaps an asynchronous database driver) which will asynchronously do some work and invoke a callback on another thread, there are a number of options to defer execution of further acteurs until the result is ready.

With support for Java 8, a variety of flexible ways to do that are available (the original mechanism, requesting injection of a Deferral object is also still supported):

  • Use then() to pass in a CompletableFuture whose result object will be serialized as the response.
  • Use continueAfter() to pass one or more CompletableFutures and have all of their results available for injection into subsequent acteurs in the chain
  • Use defer() to pause the chain and get back an instance of CompletableFuture which you can call complete() or completeExceptionally() on once the work is complete or an error has occurred
  • Use deferThenRespond() to pause the chain and get back an instance of CompletableFuture whose contents will be marshalled into the response once you call complete() or completeExceptionally().
With any of these newer methods, you should not call next() - the framework takes care of that (with an injected Deferral instance, you did). In all cases, if a CompletableFuture completes exceptionally, an error response is generated and no subsequent Acteurs are run.

With either of the methods which return a CompletableFuture, you must call complete() or completeExceptionally() no matter what happens or your application will suffer from "request dropped on the floor" bugs where the connection is held open but no response is ever sent.

Author:
Tim Boudreau
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    protected class 
     
    protected class 
    State indicating that this acteur chain is taking responsibility for responding to the request.
    static interface 
    If you write an acteur which delegates to another one, implement this so that that other one's changes to the response will be picked up.
    protected class 
    A state indicating the acteur neither accepts nor definitively refuses a request.
    class 
    A shorthand state for responding with a particular http response code and optional message, which if non-string, will be rendered as JSON.
  • Field Summary

    Fields inherited from class com.mastfrog.acteurbase.AbstractActeur

    creationStackTrace
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    protected
    Create an acteur; subclasses should simply list objects they need for processing the request as arguments, and they will be injected by Guice, either from bindings the application was set up with, or objects provided by other Acteurs which have already been run for this request.
  • Method Summary

    Modifier and Type
    Method
    Description
    protected <T> Acteur
    add(HeaderValueType<T> decorator, T value)
     
    protected final Acteur
     
    protected final Acteur
     
    protected final Acteur
    continueAfter(boolean unwrapArrays, CompletionStage<?>... stages)
    Continue the Acteur chain, running any subsequent acteurs, once the passed CompletionStages (e.g.
    protected final <T> Acteur
    continueAfter(com.mastfrog.function.throwing.ThrowingConsumer<EnhCompletableFuture<T>> c)
    Continue the acteur chain once the completable future passed to the passed consumer is consumed.
    protected final Acteur
    Continue the Acteur chain, running any subsequent acteurs, once the passed CompletionStages (e.g.
    protected final <T> EnhCompletableFuture<T>
    Pause the Acteur chain until external code completes the returned CompletableFuture, then restart the acteur chain with the result of the computation available for injection into subsequent acteurs.
    protected final <T> EnhCompletableFuture<T>
    Pause the Acteur chain until external code completes the returned CompletableFuture, then use the result of that computation as the response (JSON or whatever the application is configured to marshal responses to).
    protected final <T> EnhCompletableFuture<T>
    deferThenRespond(io.netty.handler.codec.http.HttpResponseStatus successStatus)
    Pause the Acteur chain until external code completes the returned CompletableFuture, then use the result of that computation as the response (JSON or whatever the application is configured to marshal responses to).
    protected final com.mastfrog.giulius.Dependencies
     
    void
    Provide a description used in help-page generation.
    protected <T> T
    get(HeaderValueType<T> header)
     
     
    protected com.mastfrog.acteur.ResponseImpl
     
    protected State
     
    protected final Acteur
    next(Object... context)
     
    protected final Acteur
     
    protected final Acteur
     
    protected final Acteur
     
    protected final Acteur
    ok()
     
    protected final Acteur
    ok(Object msg)
     
    protected final Acteur
     
    protected final Acteur
    reply(Err err)
     
    protected final Acteur
    reply(io.netty.handler.codec.http.HttpResponseStatus status)
     
    protected final Acteur
    reply(io.netty.handler.codec.http.HttpResponseStatus status, Object msg)
     
    protected final Response
     
    final Acteur
    setChunked(boolean chunked)
     
    final Acteur
    setMessage(Object message)
     
    final Acteur
    setResponseBodyWriter(io.netty.channel.ChannelFutureListener listener)
    Set a ChannelFutureListener which will be called after headers are written and flushed to the socket; prefer setResponseWriter() to this method unless you are not using chunked encoding and want to stream your response (in which case, be sure to chunked(false) or you will have encoding errors).
    protected final <T extends io.netty.channel.ChannelFutureListener>
    Acteur
    Set a ChannelFutureListener which will be called after headers are written and flushed to the socket; prefer setResponseWriter() to this method unless you are not using chunked encoding and want to stream your response (in which case, be sure to setChunked(false) or you will have encoding errors).
    final Acteur
    setResponseCode(io.netty.handler.codec.http.HttpResponseStatus status)
     
    protected final <T extends ResponseWriter>
    Acteur
    setResponseWriter(Class<T> writerType)
    Set a response writer which can iteratively be called back until the response is completed.
    protected final <T extends ResponseWriter>
    Acteur
    Set a response writer which can iteratively be called back until the response is completed.
    protected final Acteur
    then(com.mastfrog.function.throwing.ThrowingConsumer<Deferral.Resumer> cons)
    Defer the acteur chain, allowing the passed ThrowingConsumer to run any amount of asynchonous logic, and call Resumer.resume() with objects to be available for injection into subsequent Acteurs.
    protected final <T> Acteur
    Pass a CompletionStage (for example, CompletableFuture) which will execute asynchronously.
    protected final <T> Acteur
    then(CompletionStage<T> c, io.netty.handler.codec.http.HttpResponseStatus successStatus)
    Pass a CompletionStage (for example, CompletableFuture) which will execute asynchronously.
    static Acteur
    wrap(Class<? extends Acteur> type, com.mastfrog.giulius.Dependencies deps)
     

    Methods inherited from class com.mastfrog.acteurbase.AbstractActeur

    setState

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • Acteur

      protected Acteur()
      Create an acteur; subclasses should simply list objects they need for processing the request as arguments, and they will be injected by Guice, either from bindings the application was set up with, or objects provided by other Acteurs which have already been run for this request.
      Parameters:
      async - If true, the framework should prefer to run the next action asynchronously
  • Method Details

    • getState

      protected State getState()
      Overrides:
      getState in class AbstractActeur<Response,com.mastfrog.acteur.ResponseImpl,State>
    • getContextContribution

      public Object[] getContextContribution()
    • add

      protected <T> Acteur add(HeaderValueType<T> decorator, T value)
    • getResponse

      protected com.mastfrog.acteur.ResponseImpl getResponse()
      Overrides:
      getResponse in class AbstractActeur<Response,com.mastfrog.acteur.ResponseImpl,State>
    • get

      protected <T> T get(HeaderValueType<T> header)
    • setResponseCode

      public final Acteur setResponseCode(io.netty.handler.codec.http.HttpResponseStatus status)
    • setMessage

      public final Acteur setMessage(Object message)
    • setChunked

      public final Acteur setChunked(boolean chunked)
    • response

      protected final Response response()
      Overrides:
      response in class AbstractActeur<Response,com.mastfrog.acteur.ResponseImpl,State>
    • describeYourself

      public void describeYourself(Map<String,Object> into)
      Provide a description used in help-page generation. Acteurs which are instantiated declaratively need not override this, as information will be generated from the annotations on the acteur and any description provided
      Parameters:
      into - A map to put key/value pairs into
    • noContent

      protected final Acteur noContent()
    • badRequest

      protected final Acteur badRequest()
    • badRequest

      protected final Acteur badRequest(Object msg)
    • notFound

      protected final Acteur notFound()
    • notFound

      protected final Acteur notFound(Object msg)
    • ok

      protected final Acteur ok(Object msg)
    • ok

      protected final Acteur ok()
    • reply

      protected final Acteur reply(io.netty.handler.codec.http.HttpResponseStatus status)
    • reply

      protected final Acteur reply(io.netty.handler.codec.http.HttpResponseStatus status, Object msg)
    • reply

      protected final Acteur reply(Err err)
    • reject

      protected final Acteur reject()
    • next

      protected final Acteur next(Object... context)
    • continueAfter

      protected final Acteur continueAfter(CompletionStage<?>... stages)
      Continue the Acteur chain, running any subsequent acteurs, once the passed CompletionStages (e.g. CompletableFuture) have completed - this makes it possible to run ad-hoc asynchronous logic with the acteur chain paused, and automatically resume it when finished.
      Parameters:
      stages - One or more CompletionStage instances.
      Returns:
      This acteur
      Since:
      2.1.0
    • continueAfter

      protected final <T> Acteur continueAfter(com.mastfrog.function.throwing.ThrowingConsumer<EnhCompletableFuture<T>> c)
      Continue the acteur chain once the completable future passed to the passed consumer is consumed. The consumer is guaranteed not to be called until after the acteur constructor has exited.
      Type Parameters:
      T - The type of result that will be provided asynchronously to subsequent acteurs
      Parameters:
      c - A consumer which will receive the future
      Returns:
      this
      Since:
      2.4.1
    • continueAfter

      protected final Acteur continueAfter(boolean unwrapArrays, CompletionStage<?>... stages)
      Continue the Acteur chain, running any subsequent acteurs, once the passed CompletionStages (e.g. CompletableFuture) have completed - this makes it possible to run ad-hoc asynchronous logic with the acteur chain paused, and automatically resume it when finished.
      Parameters:
      unwrapArrays - If the object placed in a completion stage is an array, put all of its elements into context for the subsequent Acteurs, rather than the array itself
      stages - One or more CompletionStage instances.
      Returns:
      This acteur
      Since:
      2.2.2
    • deferThenRespond

      protected final <T> EnhCompletableFuture<T> deferThenRespond()
      Pause the Acteur chain until external code completes the returned CompletableFuture, then use the result of that computation as the response (JSON or whatever the application is configured to marshal responses to).
      Type Parameters:
      T - The type parameter for the returned CompletableFuture.
      Returns:
      A CompletableFuture
      Since:
      2.1.0
    • deferThenRespond

      protected final <T> EnhCompletableFuture<T> deferThenRespond(io.netty.handler.codec.http.HttpResponseStatus successStatus)
      Pause the Acteur chain until external code completes the returned CompletableFuture, then use the result of that computation as the response (JSON or whatever the application is configured to marshal responses to).
      Type Parameters:
      T - The type parameter for the returned CompletableFuture.
      Parameters:
      successStatus - The HTTP status to respond with if the result is completed normally
      Returns:
      A CompletableFuture
      Since:
      2.2.2
    • defer

      protected final <T> EnhCompletableFuture<T> defer()
      Pause the Acteur chain until external code completes the returned CompletableFuture, then restart the acteur chain with the result of the computation available for injection into subsequent acteurs.
      Type Parameters:
      T - The type parameter for the returned CompletableFuture.
      Returns:
      A CompletableFuture
      Since:
      2.1.0
    • then

      protected final Acteur then(com.mastfrog.function.throwing.ThrowingConsumer<Deferral.Resumer> cons)
      Defer the acteur chain, allowing the passed ThrowingConsumer to run any amount of asynchonous logic, and call Resumer.resume() with objects to be available for injection into subsequent Acteurs.
      Parameters:
      cons - The consumer
      Returns:
      This acteur
      Since:
      2.1.0
    • then

      protected final <T> Acteur then(CompletionStage<T> c)
      Pass a CompletionStage (for example, CompletableFuture) which will execute asynchronously. The acteur chain will be paused until the stage completes; if it completes exceptionally, the usual handling for thrown exceptions will generate the response; if it completes normally, it will be encoded as the response object (by default, to JSON).
      Type Parameters:
      T - The return type of the completion stage
      Parameters:
      c - A completion stage
      Returns:
      This acteur
      Since:
      2.1.0
    • then

      protected final <T> Acteur then(CompletionStage<T> c, io.netty.handler.codec.http.HttpResponseStatus successStatus)
      Pass a CompletionStage (for example, CompletableFuture) which will execute asynchronously. The acteur chain will be paused until the stage completes; if it completes exceptionally, the usual handling for thrown exceptions will generate the response; if it completes normally, it will be encoded as the response object (by default, to JSON).
      Type Parameters:
      T - The return type of the completion stage
      Parameters:
      c - The completion stage
      successStatus - An HttpResponseStatus to use if the stage completes normally
      Returns:
      This acteur
      Since:
      2.1.0
    • setResponseWriter

      protected final <T extends ResponseWriter> Acteur setResponseWriter(Class<T> writerType)
      Set a response writer which can iteratively be called back until the response is completed. The writer will be created dynamically but any object currently in scope can be injected into it.
      Type Parameters:
      T - The type of writer
      Parameters:
      writerType - The writer class
    • setResponseWriter

      protected final <T extends ResponseWriter> Acteur setResponseWriter(T writer)
      Set a response writer which can iteratively be called back until the response is completed.
      Type Parameters:
      T - The type of writer
      Parameters:
      writer - The writer
    • setResponseBodyWriter

      protected final <T extends io.netty.channel.ChannelFutureListener> Acteur setResponseBodyWriter(Class<T> type)
      Set a ChannelFutureListener which will be called after headers are written and flushed to the socket; prefer setResponseWriter() to this method unless you are not using chunked encoding and want to stream your response (in which case, be sure to setChunked(false) or you will have encoding errors).

      This method will dynamically construct the passed listener type using Guice, and including all of the contents of the scope in which this call was made.

      Type Parameters:
      T - a type
      Parameters:
      type - The type of listener
    • dependencies

      protected final com.mastfrog.giulius.Dependencies dependencies()
    • setResponseBodyWriter

      public final Acteur setResponseBodyWriter(io.netty.channel.ChannelFutureListener listener)
      Set a ChannelFutureListener which will be called after headers are written and flushed to the socket; prefer setResponseWriter() to this method unless you are not using chunked encoding and want to stream your response (in which case, be sure to chunked(false) or you will have encoding errors).
      Parameters:
      listener -
    • wrap

      public static Acteur wrap(Class<? extends Acteur> type, com.mastfrog.giulius.Dependencies deps)