|
From: Rod J. <rod...@in...> - 2003-03-25 10:46:52
|
Juergen, Comments inline. <jh> I've just had a look at your AOP transaction support and the PlatformTransactionManager. BTW, I agree that a true JtaTemplate object makes sense, as there already is more than one property. And your separate transaction exception hierarchy is fine too, although it currently lacks a TransactionSystemException matching JTA's general SystemException. </jh> I misunderstood: I thought you meant to make the JtaTemplate static. So I don't object quite so strongly to the use of statics as you've done. However, I think there are still strong arguments against statics. We do need a new general exception as you suggest, and we need to break down the heuristic exceptions as suggested in my TODOs in the checked in code. <jh> - First of all, I suggested to change JndiServices into a static helper class a while ago. I really don't see much value in JndiServices being a true object, as I've already stated. JndiServices effectively just simplifies context closing, there isn't great potential for extending it. For example, DataSourceUtils is a static helper too, and it uses resp. should use JndiServices... I don't mind true objects of course, it's just that we need a consistent approach to decide between static helper utils and true objects. </jh> I'm not a fan of static methods other than bootstrap methods, partly because they're hard to test. My views have probably hardened on this since I wrote the DataSourceUtils, although I think there are arguments for using statics for such trivial things. For example, if we have a static method relying on app server services such as JTA, we can't easily unit test code that uses it, because we can't replace that method by test code by overriding it or using a mock implementation of any interface. If, on the other hand, we use an object or an interface, it's possible to use mock implementations to verify that the code under test correctly invokes the methods that would otherwise be static. For example, I've easily been able to get to 80+% test coverage for TransactionInterceptor because I can create mock implementations of the PlatformTransactionManager interface that check that expectations are met about how the TransactionInterceptor should use this. I think that the ability to perform true unit testing in this way is very important. Too often J2EE code is not properly unit tested, because things can only be tested indirectly instead of testing just the behaviour of each class in isolation. Otherwise we might have to get into having a whole mock JNDI/JTA infrastructure, which could get very messy. The thing that finally convinced me that EJB is not the way forward is that both infrastructure code and app code written using it is very hard to test: I'm really keen to move away from this. <jh> - Apropos consistency: I've currently got a JtaServices class that offer static helpers for easy JTA access and implicit exception translation. Furthermore, there's a JtaTemplate class analogous to JdbcTemplate that allows for transactional execution via a callback. It uses JtaServices internally. If JndiServices were a static helper too, then we could say that XXXUtils and XXXServices were indicating static helpers while XXXTemplate were true objects. Or should we adopt a different strategy? </jh> I agree with the proposed naming and I think it's important that the XXXXTemplate is used consistently. My old JNDI stuff was inconsistent and not completely mature (I haven't done much with it for months). <jh> - Regarding PlatformTransactionManager: While the concept is obvious, I'm not entirely convinced whether it will ever be used beyond a JTA implementation. How exactly do those container-specific things like isolation level handling work? I assume they all use JTA, with some specific tweaks. Generally, could there be a viable PlatformTransactionManager that does not use JTA, especially for AOP? A JDBC-connection-based one will not work - the (non-JTA) datasource isn't even fetched from JNDI when the method call gets intercepted, and it's already returned to the pool on method call end. To me, it seems that one needs to use JTA anyway for high-level transaction management outside of the low-level resource-handling code. In this case, the PlatformTransactionManager might abstract too much - it could assume JTA and offer hooks for server-specific tweaking. </jh> In this case I think the more general solution isn't really more complex. For example, we could have a TransactionTemplate with a JtaTemplate subclass that set its PlatformTransactionManager property to use JTA. Also a TransactionInterceptor that had a JtaTransactionInterceptor subclass that did likewise. My concern about tying ourselves to JTA is mainly isolation levels. These are very important, but as far as I can see, many vendors don't expose this directly except to EJBs--JTA doesn't seem to do the job--and then vendors may expose it only to entity beans. We need the ability to get down and dirty with their proprietary APIs so that implementations can really push the buttons of each server. The most valuable implementation will probably be a straight JTA one. Also, there are a range of options such as UserTransaction, andTransaction for how we might use app server transaction capabilities. Does the PlatformTransactionManager API itself seem logical? If it doesn't constrain us, I think it does add value. I don't think efficiency is a major concern, as the cost of managing a transaction is far greater than that of calling through an interface or creating an object. <jh> - A special issue: transaction propagation. We should support taking part in transactions that already exist at interception/callback time, no matter whether from Spring or direct JTA transaction handling. Currently, JtaTemplate achieves this by explicitly checking for an existing transaction and suppressing commit resp. just setting rollback-only accordingly. More concretely, it has three propagation behavior strategies: "support existing" (do not create new one), "create new if not existing" (default), "create new always" (nesting -> not supported by most JTA implementations). </jh> Agreed. The TransactionInterceptor is similar, taking naming from the EJB spec so that it's easy for developers familiar with EJB to understand and migrate to. It's crucial that we get this right, whichever way we go. We should try to combine our efforts on this. <jh> - Concerning a common transaction infrastructure: Yep, absolutely - we need a common approach. And it needs to be simple and easy to grasp, else we don't gain much in comparison to direct JTA. So JtaTemplate should be based on the same low-level code as TransactionInterceptor. This could be my current JtaServices, your PlatformTransactionManager, or a JTA-based cousin of it. To avoid duplicated work, I will stop working on JtaTemplate until we have settled on a certain approach. </jh> OK. If we stick with PlatformTransactionManager it should probably move to com.interface21.transaction, along with the exceptions. I think we're working along very similar lines. You're JtaTemplate is very close to what I envisaged when I wrote my first email about this last week. Yann, what are your thoughts, as you were interested in transaction management? Regards, Rod |