3
votes

If a Play controller retrieves a values from the Request (e.g. logged in user and his role) and those values need to be passed to all the layers down to controllers (e.g. service layer, DAO layer etc) what's the best way to create a "threadlocal" type of object, which can be used by any class in the Application to retrieve those "user" and "userRole" values for that particular request? I am trying to avoid adding implicit parameters to a bunch of methods and Play Cache doesn't look like an appropriate fit here. Also play's different scope (session, flash etc) wouldn't behave right given all the code is asynchronous. Controller methods are async, service methods returns Future etc. That "threadlocal" type of effect in an asynchronous environment is desired.

1

1 Answers

1
votes

Alternatives that are not a good fit

These alternatives are probably not helpful, because they assume a global state accessible by all functions across the processing of a request:

  • Thread local storage is a technique that is helpful for applications that process the request in a single thread, and that block until a response is generated. Although it's possible to do this with Play Framework, it's usually not the optimal design, since Play's strengths are of more benefit for asynchronous, non-blocking applications.

  • Session and flash are meant to carry data across HTTP requests. They're not globally available to all classes in an application; it would be necessary to pass the modified request across function calls to retrieve them.

  • A cache could in theory be used to carry this information, but it would have to have a unique key for each request, and it would be necessary to pass this key in each function call. Additionally, it would be necessary to make sure the cache data is not at risk of being evicted while processing the request, not even when cache memory is full.

Alternatives that may be a good fit

Assuming the controller, possibly though the Action call, retrieves the security data (user, role, etc.), and that the controller only deals with validating the request and generating a response, delegating domain logic to a domain object (possibly a service object):

  • Using the call stack: Pass the security data to all functions that need it, through an implicit parameter. Although the question is about finding an alternative to doing that, this approach makes it explicit what is being sent to the called function, and which functions require this data, instead of resorting to state maintained elsewhere.

  • Using OOP: Pass the security data in the constructor of the domain object, and in the domain object's methods, retrieve the security data from the object's instance.

  • Using actors: Pass the security data in the message sent to the actor.

If a domain object's method calls a function that also needs the security data, the same pattern would be applied: either pass it as (a possibly implicit) parameter, through a constructor, or in a message.