Community   SpringSource   Projects    Downloads    Documentation    Forums    Training   Exchange   Blogs

Go Back   Spring Community Forums > Core Spring Projects > AOP (Aspect Oriented Programming)

Reply
 
Thread Tools Display Modes
  #1  
Old Sep 1st, 2006, 11:36 AM
mraible mraible is offline
Senior Member
 
Join Date: Aug 2004
Location: Denver
Posts: 247
Default Migrating from txProxyTemplate to <aop:config>

I'm trying to migrate from the old 1.2.x style to the 2.0 XSD style. Here's what I have in 1.2.8:

Code:
   
    <!-- Transaction template for Managers, from:
         http://blog.exis.com/colin/archives/2004/07/31/concise-transaction-definitions-spring-11/ -->
    <bean id="txProxyTemplate" abstract="true"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="save*">PROPAGATION_REQUIRED</prop>
                <prop key="remove*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>
    </bean>

    <!-- Generic manager that can be used to do basic CRUD operations on any objects -->
    <bean id="manager" parent="txProxyTemplate">
        <property name="target">
            <bean class="org.appfuse.service.impl.BaseManager">
                <property name="dao" ref="dao"/>
            </bean>
        </property>
    </bean>
    
    <!-- Transaction declarations for business services.  To apply a generic transaction proxy to
         all managers, you might look into using the BeanNameAutoProxyCreator -->
    <bean id="userManager" parent="txProxyTemplate">
        <property name="target">
            <bean class="org.appfuse.service.impl.UserManagerImpl">
                <property name="userDao" ref="userDao"/>
            </bean>
        </property>
        <!-- Override default transaction attributes b/c of UserExistsException -->
        <property name="transactionAttributes">
            <props>
                <prop key="save*">PROPAGATION_REQUIRED,-UserExistsException</prop>
                <prop key="remove*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>
        <!-- This property is overriden in applicationContext-security.xml to add
             method-level role security -->
        <property name="preInterceptors">
            <list>
                <ref bean="userSecurityInterceptor"/>
            </list>
        </property>
    </bean>

    <!-- This interceptor insures that that users can only update themselves, not other users -->
    <bean id="userSecurityInterceptor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="userSecurityAdvice"/>
        <property name="patterns" value=".*saveUser"/>
    </bean>

    <bean id="userSecurityAdvice" class="org.appfuse.service.UserSecurityAdvice">
        <property name="userCache" ref="userCache"/>
    </bean>
Using 2.0, I'm guessing this same advice is applied using the following:

Code:
<aop:config>
        <aop:advisor id="serviceMethods" pointcut="execution(* *.service.*Manager.*(..))" advice-ref="txAdvice"/>
        <aop:advisor id="userManagerMethods" pointcut="execution(* *.service.UserManager.*(..))"
                     advice-ref="userManagerTxAdvice"/>
        <aop:advisor id="userManagerSecurity" pointcut="execution(* *.service.UserManager.saveUser(..))"
                     advice-ref="userSecurityAdvice"/>
    </aop:config>

    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <tx:advice id="userManagerTxAdvice">
        <tx:attributes>
            <tx:method name="save*" rollback-for="UserExistsException"/>
            <tx:method name="remove*"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- Generic manager that can be used to do basic CRUD operations on any objects -->
    <bean id="manager" class="org.appfuse.service.impl.BaseManager">
        <property name="dao" ref="dao"/>
    </bean>

    <bean id="userManager" class="org.appfuse.service.impl.UserManagerImpl">
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean id="userSecurityAdvice" class="org.appfuse.service.UserSecurityAdvice">
        <property name="userCache" ref="userCache"/>
    </bean>
I'd like to say this works, but it doesn't. I get tests that fail because I'm calling save() in a read-only transaction. I'm using Spring 2.0-rc1. I tried using rc2 (the latest version in ibiblio) and everything blows up when initializing.

I thought removing the read-only flag from userManagerTxAdvice would work, but no dice, the issue still happens.

Code:
    <tx:advice id="userManagerTxAdvice">
        <tx:attributes>
            <tx:method name="save*" rollback-for="UserExistsException"/>
            <tx:method name="remove*"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
Stack trace:

Code:
[INFO] [talledLocalContainer] Caused by: javax.faces.el.EvaluationException: Exception while invokin
g expression #{signupForm.save}
[INFO] [talledLocalContainer]   at org.apache.myfaces.el.MethodBindingImpl.invoke(MethodBindingImpl.
java:153)
[INFO] [talledLocalContainer]   at org.apache.myfaces.application.ActionListenerImpl.processAction(A
ctionListenerImpl.java:63)
[INFO] [talledLocalContainer]   ... 78 more
[INFO] [talledLocalContainer] Caused by: org.springframework.dao.InvalidDataAccessApiUsageException:
 Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into Flush
Mode.AUTO or remove 'readOnly' marker from transaction definition
[INFO] [talledLocalContainer]   at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOp
erationAllowed(HibernateTemplate.java:1082)
__________________
http://raibledesigns.com

Last edited by mraible; Sep 1st, 2006 at 11:45 AM.
Reply With Quote
  #2  
Old Sep 5th, 2006, 10:45 PM
dsklyut dsklyut is offline
Senior Member
 
Join Date: Dec 2005
Location: Philadelphia, PA, USA
Posts: 227
Default

It might not be this simple but, have you tried changing your pointcuts to something a little more specific? It looks like all three pointcuts would match UserManager.saveUser joinpoint.

Code:
<aop:config>
        <aop:advisor id="serviceMethods" pointcut="execution(* *.service.*Manager.*(..)) and !within(*.service.UserManager)" advice-ref="txAdvice"/>
        <aop:advisor id="userManagerMethods" pointcut="within(*.service.UserManager)"
                     advice-ref="userManagerTxAdvice" order="2"/>
        <aop:advisor id="userManagerSecurity" pointcut="execution(* *.service.UserManager.saveUser(..))"
                     advice-ref="userSecurityAdvice" order="1"/>
    </aop:config>
I hope this works.
Reply With Quote
  #3  
Old Sep 6th, 2006, 03:54 PM
mraible mraible is offline
Senior Member
 
Join Date: Aug 2004
Location: Denver
Posts: 247
Default

As far as I can tell, it appears that AspectJ's pointcut language does not support using wildcards (*) for package names. The following seems to work:

Code:
    <aop:config>
        <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* org.appfuse.service.*Manager.*(..))"/>
        <aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="within(org.appfuse.service.UserManager)"/>
        <aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* org.appfuse.service.UserManager.saveUser(..))"/>
    </aop:config>
It'd be nice to figure out a way to make the "managerTx" advisor more generic so applications that use AppFuse could have this advice applied even when classes are in a different package than org.appfuse.service.
__________________
http://raibledesigns.com
Reply With Quote
  #4  
Old Sep 6th, 2006, 04:39 PM
dsklyut dsklyut is offline
Senior Member
 
Join Date: Dec 2005
Location: Philadelphia, PA, USA
Posts: 227
Default

Try this:
http://www.eclipse.org/aspectj/doc/n...ePatterns.html

I think "*" is for characters and ".." is for packages/sub-packages.

Maybe an expression like this:
Code:
execution(* *..*Manager.*(..))"
Don't have a way to test it right now.

Another way is to define a named pointcut outside the advisor and reference it with pointcut-ref. In that case you can choose a type of pointcut - aspectj or regex.

Something like this:
Code:
<aop:config>
  <aop:pointcut id="test" type="regex"  expression="*.UserManager.saveUser"/>
</aop:config>
This way you should be able to use 1.2 style regex poincut expression vs. AspectJ.

Dmitry
Reply With Quote
  #5  
Old Sep 6th, 2006, 06:05 PM
mraible mraible is offline
Senior Member
 
Join Date: Aug 2004
Location: Denver
Posts: 247
Default

I tried the following, but no luck:

Code:
    <aop:config>
        <aop:pointcut id="serviceMethodsPointcut" type="regex" expression="*Manager.*"/>
        <aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="execution(* org.appfuse.service.UserManager.*(..))" order="0"/>        
        <aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* org.appfuse.service.UserManager.saveUser(..))" order="1"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethodsPointcut" order="2"/>    
    </aop:config>
But this results in:

Caused by: java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'identifier' at character position 0
*Manager.*
^

The following works, but is missing the benefit of wrapping transactions around any beans with service.*Manager in their package/class name.

Code:
    <aop:config>
        <aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="execution(* org.appfuse.service.UserManager.*(..))" order="0"/>        
        <aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* org.appfuse.service.UserManager.saveUser(..))" order="1"/>
        <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* org.appfuse.service..*Manager.*(..))" order="2"/>
    </aop:config>
__________________
http://raibledesigns.com
Reply With Quote
  #6  
Old Sep 6th, 2006, 08:39 PM
ramnivas ramnivas is offline
Senior Member
 
Join Date: Jun 2006
Location: SF Bay Area, California
Posts: 523
Default Try this...

Dmitry's suggestion of execution(* *..*Manager.*(..)) should really work.

Can you try the following:

Code:
<aop:config>
    <aop:pointcut id="serviceMethodsPointcut" expression="execution(* *..*Manager.*(..))"/>
    <aop:advisor id="userManagerTx" advice-ref="userManagerTxAdvice" pointcut="execution(* org.appfuse.service.UserManager.*(..))" order="0"/>        
    <aop:advisor id="userManagerSecurity" advice-ref="userSecurityAdvice" pointcut="execution(* org.appfuse.service.UserManager.saveUser(..))" order="1"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethodsPointcut" order="2"/>    
</aop:config>
-Ramnivas
__________________
Ramnivas Laddad (Follow me on Twitter)
AspectJ in Action: Enterprise AOP with Spring Applications (2nd edition). Now available!
Reply With Quote
  #7  
Old Sep 6th, 2006, 08:48 PM
mraible mraible is offline
Senior Member
 
Join Date: Aug 2004
Location: Denver
Posts: 247
Default

If I use:

Code:
<aop:pointcut id="serviceMethodsPointcut" expression="execution(* *..*Manager.*(..))"/>
It results in:

Code:
[applicationContext-service.xml]: Invocation of init method failed; nested exception is 
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.NullPointerException
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException
	at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:431)
Obviously, the pointcut express is too broad. If I change it to:

Code:
expression="execution(* *.service..*Manager.*(..))"
... it works great - thanks!
__________________
http://raibledesigns.com
Reply With Quote
  #8  
Old Sep 6th, 2006, 08:59 PM
ramnivas ramnivas is offline
Senior Member
 
Join Date: Jun 2006
Location: SF Bay Area, California
Posts: 523
Default

You're welcome.

You probably need the following modification to your pointcut (simply move the '..' portion) Since it is working for you, I suspect you already have this or a similar change.

Code:
expression="execution(* *..service.*Manager.*(..))"
to select the service.*Manager type regardless of the parent package structure.

-Ramnivas
__________________
Ramnivas Laddad (Follow me on Twitter)
AspectJ in Action: Enterprise AOP with Spring Applications (2nd edition). Now available!
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 08:06 AM.


Contegix provides first-class managed hosting and partial sponsorship of these forums.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.