View Full Version : Catching & treating certain exceptions
nokiola
08-07-2006, 03:23 PM
Hello,
I am using Transaction attribute in my Spring.NET + NHibernate application.
1. Any examples outthere where I can find out how can I perform some tasks before the transaction is rolled back due to some exception?
2. How can I make the TransactionInterceptor not to roll back a transaction in case that a certain exception occured? I do not want that all exceptions to trigger a rollback.
Regards,
Robert
Mark Pollack
08-08-2006, 01:46 PM
Hi Robert,
If you have a service method that is being transactionally adviced, i.e.
[Transaction]
public void DoSomeStuff()
{
// do stuff
}
The rollback happens once the exception propagates outside the DoSomeStuff method and is handled by the TransactionInterceptor. You can either catch and rethrow the exception "inline" with the business service code or you can create another interceptor and add it to the interceptor chain - this interceptor would act as a centralized exception handling aspect. (Integration with MS Exception handling app block would be nice...)
What does your configuration look like, i.e. how are you doing your tx managment? I can put a quick example together but since there are many ways to do tx mgmt it would be better to focus on your usage scenario.
Another alternative is to register a "transaction synchronization", that is a class that implements the ITransactionSyncrhonization interface which has a method
void AfterCompletion( TransactionSynchronizationStatus status );
You register for this callback using the static method on the class TransactionSynchronizationManager.RegisterSynchron ization. You can check the enum value on the status and decide what to do in that way.
As for the second question, I got ~1/2 way implementing that feature. I need to get back to it.
Cheers,
Mark
nokiola
08-08-2006, 02:16 PM
I've attached the spring configuration xml and the AccountService class which is responsible for managing Account POCO classes
public class AccountServices : IAccountServices
{
private IAccountDAO accountDAO;
public IAccountDAO AccountDAO
{
get { return accountDAO; }
set { accountDAO = value; }
}
[Transaction()]
public Account CreateAccount(Account account)
{
return accountDAO.Save(account);
}
[Transaction()]
public void DeleteAccount(Account account)
{
accountDAO.Delete(account);
}
[Transaction()]
public void UpdateAccount(Account account)
{
accountDAO.SaveOrUpdate(account);
}
public Account GetAccount(int ID)
{
return accountDAO.Get(ID, false);
}
}
Can you show me an example of how to catch/intercept centrally exceptions? I assume a new interceptor will be needed which treats the exception.
R.
Mark Pollack
01-04-2007, 05:12 AM
Hi Robert,
I've added to the transaction quickstart some exception processing and handling advice/interceptors and also the various ways you can add these to the configuration for creating transactional proxies. The key point regarding advice and exceptions is do distinguish between the cases of exception processing as compared to handling.
You can use "throws advice" (implement IThrowsAdvice) only to perform processing tasks, say logging or exception translation, but not to handle/catch the exception. If no exception translation is done inside the throws advice the calling code will see the original exception. If the throws advice performs exception translation, i.e. in the implementation it throws a new (translated) exception, then that will be seen by the calling code. In either case, throws advice can not handle the exception. In order to handle the exception you need to use around advice (implement IMethodInterceptor).
In the transaction quickstart I created two simple implementations of throws advice, ExceptionLoggingProcessor and SimpleExceptionProcessor. ExceptionLoggingProcessor simply logs all thrown exceptions. SimpleExceptionProcessor has two methods, one for the processing a DataAccessException and another to process all other exception types.
Moving up the ladder in complexity I created a throws advice, ExceptionTranslationProcessor, that delegates to an implementation of IExceptionTranslator to perform exception translation. You can then use normal dependency injection techniques to configure the throws advice with an implementation of IExceptionTranslator as any other object configured by Spring. SimpleExceptionTranslator converts ArithmeticException to ArgumentOutOfRangeException (not very realistic I know…)
Lastly, I created a similar style around advice, ExceptionHandlingInterceptor, that delegates to an implementation of IExceptionHandler that can choose to actually handle/catch the advice. This could prevent the calling code from seeing the exception. There is a LoggingExceptionHandler that just logs and I got 1/2 way with a "MappingExceptionTranslator" but didn't finish it - this would be something along the lines of MS EnterpriseLibrary.
To apply this advice in addition to the transactional interceptor depends on how you create your proxy. The config file, DTCAppContext.xml shows the various options. For the case of a ProxyFactoryObject, add the interceptor name to the "InterceptorNames" property along with the name of the transaction interceptor. For the case of TransactionProxyFactoryObject you can specify the name of the interceptor in either the "PreInterceptors" or "PostInterceptors" property. The pre-post is with respect to the transaction interceptor. For ObjectNameAutoProxyCreator add the intercetor name to the "InterceptorNames" property. For DefaultAdvisorAutoProxyCreator you should use AttributeMatchMethodPointcutAdvisor to associate the exception handling/processing advice with the [Transaction] attribute pointcut in addition to specifying a TransactionAttributeSourceAdvisor. In this last case the Order property determines the ordering of the interceptors, otherwise it is based on the order of the interceptor names in the list.
In this data access case, there is one assumption build into all the above configurations that you should be aware of. The proxy created will have the interceptor chain created for each method on the DAO interface (assuming you don’t ask to proxy virtual methods as well.) However, the transaction interceptor only works on those methods with the attribute because the interceptor checks for the presence of the transaction metata associated with the executing method before doing its job. (This also applies for other sources of the transaction metadata, i.e. inside XML, and not just attributes.). The other interceptors in the chain don't do similar checks based on the presence of tx metadata associated with the method so they will always be "active". This means that the exception handling interceptor (or any other) would apply to interface methods that didn't have the [Transaction] attribute. These could also be other non DAO interfaces that your DAO implementation happens to implement.
To avoid this situation you can either use AttributeMatchMethodPointcutAdvisor based on the [Transaction] attribute, but that doesn't cover the case of XML based declarative tx pointcut configuration. To solve this problem I created the class DefaultTransactionAttributeSourceAdvisor, which takes as arguments a transactionAttributeSource and any advice. This works nicely when using the DefaultAdvisorAutoProxyCreator approach to configuration. There maybe a way for the other types of configuration but I need to think more. Hopefully, this won't matter too much in practice. Spring.Java always 'suffered' from this limitation until Spring 2.0, and it didn't have the workaround based on DefaultTransactionAttributeSourceAdvisor that I just created.
I realize this is a long rather complicated response…let me know if you have any additional questions and get the latest example code to see what I’m talking about.
Mark
Powered by vBulletin® Version 4.1.5 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.