[2.4.6 - java] Action's annotations are executing before the RequestHandler's createAction or Global's onRequest

146 views
Skip to first unread message

Rajendra Prasad Gujja

unread,
Jan 8, 2016, 1:01:46 AM1/8/16
to play-framework
Hello Community,

We are evaluating Play to re-write our multi-tenant JPA application, we have started using Play Java as most of our team familiar with it. 

My problem here is, I am trying to use Hibernate's multi-tenant feature (db per tenant), where I can switch the data sources based on an attribute in Http.Context.args. I am planning to set this attribute for all the requests either using RequestHandler or Global.  The actions in my controllers are annotated with the @Transactional.

The actual behaviour is @Transactional is being intercepted before the Global's onRequest and trying to set the JPA EntityManager in Http.Context and failing because It can not find tenant attribute while trying to figure out the specific tenant.

What is the preferred way to intercept all the requests (even better all requests with particular router pattern) before any annotations on actual action being triggered?

My controller action:

@Transactional
public Result list() {
Set<UnitEntity> units = UnitEntity.findAll(UnitEntity.class);
return ok(Json.toJson(units));
}


My RequestHandler:

@Override
public Action createAction(Http.Request request, Method actionMethod) {
return new Action.Simple() {
@Override
public F.Promise<Result> call(Http.Context ctx) throws Throwable {
Map<String, Object> args = ctx.args;
args.put("tenantId", "uchealth");
return delegate.call(ctx);
}
};
}

application.conf
play.http.requestHandler="common.IRequestHandler"


I am missing some basic concepts of the flow. Could please somebody help me?

Thanks,
Raj.

Matthias Kurz

unread,
Jan 8, 2016, 6:34:17 AM1/8/16
to play-framework
(First of all: Don't use Global - it is deprecated and will be removed in Future versions of Play.)

Maybe that's the way to go.

Rajendra Prasad Gujja

unread,
Jan 8, 2016, 1:01:39 PM1/8/16
to play-framework
Hi Matthias,

Thank you very much for your reply.

I have considered the action composition but I thought annotating each method in every controller is a painful task. Can I annotate an action composition at the controller level? also, in which order action compositions execute if there are more than one composition present?

Also, is there a way I can hook my filter just before any action composition of an action is executed?

Thanks,
Raj.

Matthias Kurz

unread,
Jan 8, 2016, 8:09:05 PM1/8/16
to play-framework
> Can I annotate an action composition at the controller level?
Yes, read the docs:
"You can also put any action composition annotation directly on the Controller class. In this case it will be applied to all action methods defined by this controller."

By default the action method's annotations come before the ones defined at controller level. Just one sentence below in the docs there is this explanation about the order:
"Note: If you want the action composition annotation(s) put on a Controller class to be executed before the one(s) put on action methods set play.http.actionComposition.controllerAnnotationsFirst = true in application.conf. However, be aware that if you use a third party module in your project it may rely on a certain execution order of its annotations."

You could also make one "super" controller which all other controllers inherit from to make it even more easy. For example:
@SetupJPA // Always runs first
@Transactional // runs after @SetupJPA
public class BaseController extends Controller { ... }

@SomeOtherAnnotationABC // runs after @Transactional
public class ControllerOne extends BaseController {

    public Result index() { ... }
}

@SomeOtherAnnotationXYZ // runs after @Transactional
public class ControllerTwo extends BaseController {

    // @RunsBeforeClassAnnotations -> If you put one here it will run even BEFORE @SetupJPA because of how ordering works
    // (can be changed via play.http.actionComposition.controllerAnnotationsFirst = true)
public Result logout() { ... } }
I hope you get the idea of how this works.
Just make some test annotations to find out how this works.

About filters:
First read the documentation ("Where do filters fit in?"). I am not sure if filters are really what you want in your case (maybe the filter would also run for simple assets like images, javascripts files etc.?)
You would have to write them in Scala as well.

Also check out this bug report, it may be of interest for your: https://github.com/playframework/playframework/issues/1088 - Maybe Play's behavious will change in Future so the RequestHandler will be called before action composition annotations in future.

Greetings,
Matthias

Rajendra Prasad Gujja

unread,
Jan 8, 2016, 8:22:42 PM1/8/16
to play-framework
Thank you very much for the clarification, Matthias.

I will play with class level annotations. For now, I removed the @Transactional from the controller and using JPA.withTransaction() in service. The issue link that you provided is the one exactly I was talking about.

Thank you very much again!

Happy weekend!
-Raj.

Matthias Kurz

unread,
Jan 22, 2016, 5:14:13 AM1/22/16
to play-framework
Hi Raj,

just an update:
Starting with Play 2.5 you can also use RequestHandler.createAction as the place to hook into before any action composition happens (which therefore also applies for Global.onRequest).
That's because we added a new setting in Play 2.5:

If you are also using JavaActionsComposition then the action returned by the createAction method of the request handler is executed after the action composition ones by default. If you want to change this order set play.http.actionComposition.executeRequestHandlerActionFirst = true in application.conf.


Maybe you prefer this way more than having a "super-controller-class".

Matthias

Rajendra Prasad Gujja

unread,
Jan 22, 2016, 1:04:16 PM1/22/16
to play-framework
Hi Matthias,

This is really helpful. I will definitely use this as soon as 2.5 public release available, we are closely following the changes.

Thank you very much for your efforts to fix it. I tried to contribute on this, but your fix is more reliable and flexible than my hack.

Thanks,
Raj.
Reply all
Reply to author
Forward
0 new messages