As a basis, I'm assuming the approach where one user interaction should normally result in one DB transaction, so that the whole interaction can either fail or succeed, atomically.
The first thing to consider with RequestFactory is, that each method call in a RequestContext can succeed or fail individually. Also note, that the fire() call will (usually) succeed as a whole, even if one of the RequestContext method calls fails.
So for example, if you have
ctx.opA().to(receiverA);
ctx.opB().to(receiverB);
ctx.fire(receiverX);
Then this may result in the sequence
receiverA.onSuccess(),
receiverB.onFailure(),
receiverX.onSuccess().
What this means is, that you get atomicity only for the individual RequestContext methods. Therefore you definitely shouldn't wrap the entire RequestFactoryServlet's onPost() method in one transaction, but rather only the individual service method implementations individually. (Otherwise, the client may believe, that opA has succeeded, while in reality the entire transaction was rolled back.)
And if you need a transaction with multiple objects involved, you will have to wrap the entire interaction in one service method call.
Side note: Convenience solution
If you grow tired of wrapping each service method implementation in a transaction individually, you may want to use your own ServiceLayerDecorator in the RequestFactoryServlet constructor, and override invoke() like this:
@Override
public Object invoke(final Method domainMethod, final Object... args) {
// Note: Ideally use dependency injecton for this:
final EntityManager em = getRequestScopedEntityManager();
try {
em.getTransaction().begin();
final Object result = super.invoke(domainMethod, args);
em.getTransaction().commit();
return result;
} catch (final Error e) {
em.getTransaction().rollback();
throw e;
} catch (final RuntimeException e) {
em.getTransaction().rollback();
throw e;
}
}
(Better solutions are welcome!)
Question/Discussion:
There is however a little issue that remains: RequestFactory calls Locator.find() outside of such a transaction:
- In RequestState.getBeansForPayload(), which calls ServiceLayerDecorator.loadDomainObjects()
- In SimpleRequestProcessor.createReturnOperations, which calls ServiceLayerDecorator.isLive()
I think, it's possible to pretty much ignore this (at least if you don't use isolation levels higher than READ_COMMITTED, and if your DB is ok with autocommit style queries), or is it? Note: My Locator's find method re-uses the same RequestScoped EntityManager instance - so I get the same underlying Hibernate session with the same first-level cache - it's just not in the same transaction, that's all.
How do you deal with this? What is the intended transaction concept by the RequestFactory designers?
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/ASBa77ljy3cJ.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
No comments:
Post a Comment