1. Make transactionInterceptor accessible from Spring IOC context.

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
          p:sessionFactory-ref="sessionFactory"/>

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
    <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"
          p:transactionInterceptor-ref="transactionInterceptor"/>

    <bean id="transactionInterceptor"
          class="org.springframework.transaction.interceptor.TransactionInterceptor"
          p:transactionManager-ref="transactionManager"
          p:transactionAttributeSource-ref="transactionAttributeSource"/>

    <bean id="transactionAttributeSource"
          class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
        <constructor-arg value="false"/>
    </bean>

2. Contribute transactional worker to components transformation chain.

   1     public static void contributeComponentClassTransformWorker(OrderedConfiguration<ComponentClassTransformWorker> configuration,
   2             TransactionInterceptor transactionInterceptor) {
   3         configuration.add("Transactional", new TransactionalWorker(transactionInterceptor));
   4     }

3. Create TransactionalWorker.

   1 public class TransactionalWorker implements ComponentClassTransformWorker {
   2     private final TransactionInterceptor transactionInterceptor;
   3     private final ComponentMethodAdvice advice = new ComponentMethodAdvice() {
   4         public void advise(final ComponentMethodInvocation invocation) {
   5             try {
   6                 transactionInterceptor.invoke(new MethodInvocationAdapter(invocation));
   7                 if (invocation.isFail()) {
   8                     throw new RuntimeException(invocation.getThrown(Throwable.class));
   9                 }
  10             }
  11             catch (RuntimeException ex) {
  12                 throw ex;
  13             } catch (Throwable ex) {
  14                 throw new RuntimeException(ex);
  15             }
  16         }
  17     };
  18 
  19     public TransactionalWorker(TransactionInterceptor transactionInterceptor) {
  20         this.transactionInterceptor = transactionInterceptor;
  21     }
  22 
  23     public void transform(ClassTransformation transformation, MutableComponentModel model) {
  24         for (TransformMethodSignature sig : transformation.findMethodsWithAnnotation(Transactional.class)) {
  25             transformation.advise(sig, advice);
  26         }
  27     }
  28 }

4. Implement MethodInvocation adapter.

   1 import org.aopalliance.intercept.MethodInvocation;
   2 import org.apache.tapestry.services.ComponentMethodInvocation;
   3 
   4 import java.lang.reflect.AccessibleObject;
   5 import java.lang.reflect.Method;
   6 
   7 class MethodInvocationAdapter implements MethodInvocation {
   8     private final ComponentMethodInvocation invocation;
   9 
  10     public MethodInvocationAdapter(ComponentMethodInvocation invocation) {
  11         this.invocation = invocation;
  12     }
  13 
  14     public Object getThis() {
  15         return invocation.getComponentResources().getComponent();
  16     }
  17 
  18     public Method getMethod() {
  19         Method method = BeanUtils.findDeclaredMethod(getThisClass(), invocation.getMethodName(), getParameterTypes());
  20         if (method != null) {
  21             return method;
  22         }
  23         throw new RuntimeException(invocation.getMethodName() + " not found");
  24     }
  25 
  26     private Class getThisClass() {
  27         Class clazz = getThis().getClass();
  28         try {
  29             return Class.forName(clazz.getName()); // ClassLoader issue
  30         } catch (ClassNotFoundException e) {
  31             return clazz;
  32         }
  33     }
  34 
  35     private Class[] getParameterTypes() {
  36         int parameterCount = invocation.getParameterCount();
  37         Class[] classes = new Class[parameterCount];
  38         for (int i = 0; i < parameterCount; i++) {
  39             classes[i] = invocation.getParameterType(i);
  40         }
  41         return classes;
  42     }
  43 
  44     public Object proceed() throws Throwable {
  45         invocation.proceed();
  46         return invocation.getResult();
  47     }
  48 
  49     public Object[] getArguments() {
  50         int parameterCount = invocation.getParameterCount();
  51         Object[] args = new Object[parameterCount];
  52         for (int i = 0; i < parameterCount; i++) {
  53             args[i] = invocation.getParameter(i);
  54         }
  55         return args;
  56     }
  57 
  58     public AccessibleObject getStaticPart() {
  59         throw new UnsupportedOperationException();
  60     }
  61 }

5. Annotate component method and run.

   1  @Transactional(readOnly = true)
   2     void setupRender() {
   3 
   4     }

written by Michael Kretinin

Tapestry5_How_To_Integrate_Components_With_Spring_Transactions (last edited 2009-09-20 23:20:57 by localhost)